Skip to content

Take Bug fixes to Master #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
May 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8919af7
Fix exceptions in importing CustomizedRule
yutingc May 4, 2015
ff75584
Revert "Fix exceptions in importing CustomizedRule"
yutingc May 4, 2015
53ca175
Fix bugs in importing external rule
yutingc May 4, 2015
c5f1ecc
Updated string comparison
yutingc May 4, 2015
89b4e23
Modified string comparison options
yutingc May 4, 2015
be781aa
Added unit test
yutingc May 4, 2015
b73aa4d
Added unit tests
yutingc May 5, 2015
cdcc4e5
Added changes in ExternalRule
yutingc May 5, 2015
5eff3c4
Merge pull request #90 from PowerShell/customizedRule
yutingc May 5, 2015
49c0e1e
Suppress write host for function that starts with show
May 5, 2015
5b0785b
Merge pull request #93 from PowerShell/writehostbug
May 5, 2015
6cb8120
Updated existing rule for verifiying the presence of WMI cmdlets in a…
raghushantha May 5, 2015
5e2a145
Updated existing rule for verifiying the presence of WMI cmdlets in a…
raghushantha May 5, 2015
dcb5d6e
Tests for [AvoidUsingWMICmdlet Rule
raghushantha May 5, 2015
f00cfa6
Merge pull request #98 from PowerShell/AvoidUsingWMICmdletBranch
raghushantha May 5, 2015
4238f90
Do not require Write-Verbose in scripts or functions without the Cmdl…
GoodOlClint May 6, 2015
958e65d
Merge pull request #100 from GoodOlClint/BugFixes
yutingc May 6, 2015
4f8e7a6
Revert "Only Trigger PSProvideVerboseMessage in Advanced Scripts or F…
yutingc May 6, 2015
c488f10
Merge pull request #101 from PowerShell/revert-100-BugFixes
yutingc May 6, 2015
3aa8ee8
Revert "Revert "Only Trigger PSProvideVerboseMessage in Advanced Scri…
yutingc May 6, 2015
974a255
Merge pull request #102 from PowerShell/revert-101-revert-100-BugFixes
yutingc May 6, 2015
f3b55e6
Rule Documentation for WMI Cmdlet
raghushantha May 6, 2015
72858d2
Update AvoidUsingWMICmdlet.md
raghushantha May 6, 2015
6f2a57b
Update AvoidUsingWMICmdlet.md
raghushantha May 6, 2015
5e7d2f6
Update AvoidUsingWMICmdlet.md
yutingc May 6, 2015
350816b
Merge pull request #105 from PowerShell/AvoidWMICmdletRuleDocumentati…
raghushantha May 6, 2015
a29203d
Revert "Revert "Revert "Only Trigger PSProvideVerboseMessage in Advan…
yutingc May 6, 2015
f12e076
Merge pull request #107 from PowerShell/revert-102-revert-101-revert-…
yutingc May 6, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Engine/Generic/ExternalRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal class ExternalRule : IExternalRule
string param = string.Empty;
string srcName = string.Empty;
string modPath = string.Empty;

string paramType = string.Empty;

public string GetName()
{
Expand All @@ -55,6 +55,11 @@ public SourceType GetSourceType()
return SourceType.Module;
}

public string GetParameterType()
{
return this.paramType;
}

//Set the community rule level as warning as the current implementation does not require user to specify rule severity when defining their functions in PS scripts
public RuleSeverity GetSeverity()
{
Expand All @@ -80,14 +85,15 @@ public ExternalRule()

}

public ExternalRule(string name, string commonName, string desc, string param, string srcName, string modPath)
public ExternalRule(string name, string commonName, string desc, string param, string paramType, string srcName, string modPath)
{
this.name = name;
this.commonName = commonName;
this.desc = desc;
this.param = param;
this.srcName = srcName;
this.modPath = modPath;
this.paramType = paramType;
}

#endregion
Expand Down
102 changes: 58 additions & 44 deletions Engine/ScriptAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public void Initilaize(Dictionary<string, List<string>> result)
paths = result.ContainsKey("ValidDllPaths") ? result["ValidDllPaths"] : result["ValidPaths"];
foreach (string path in paths)
{
if (Path.GetExtension(path).ToLower(CultureInfo.CurrentCulture) == ".dll")
if (String.Equals(Path.GetExtension(path),".dll",StringComparison.OrdinalIgnoreCase))
{
catalog.Catalogs.Add(new AssemblyCatalog(path));
}
Expand Down Expand Up @@ -241,8 +241,8 @@ public List<ExternalRule> GetExternalRule(string[] moduleNames)

FunctionInfo funcInfo = (FunctionInfo)psobject.ImmediateBaseObject;
ParameterMetadata param = funcInfo.Parameters.Values
.First<ParameterMetadata>(item => item.Name.ToLower(CultureInfo.CurrentCulture).EndsWith("ast", StringComparison.CurrentCulture) ||
item.Name.ToLower(CultureInfo.CurrentCulture).EndsWith("token", StringComparison.CurrentCulture));
.First<ParameterMetadata>(item => item.Name.EndsWith("ast", StringComparison.OrdinalIgnoreCase) ||
item.Name.EndsWith("token", StringComparison.OrdinalIgnoreCase));

//Only add functions that are defined as rules.
if (param != null)
Expand All @@ -251,7 +251,7 @@ public List<ExternalRule> GetExternalRule(string[] moduleNames)
string desc =posh.AddScript(script).Invoke()[0].ImmediateBaseObject.ToString()
.Replace("\r\n", " ").Trim();

rules.Add(new ExternalRule(funcInfo.Name, funcInfo.Name, desc, param.Name,
rules.Add(new ExternalRule(funcInfo.Name, funcInfo.Name, desc, param.Name,param.ParameterType.FullName,
funcInfo.ModuleName, funcInfo.Module.Path));
}
}
Expand Down Expand Up @@ -289,13 +289,13 @@ public IEnumerable<DiagnosticRecord> GetExternalRecord(Ast ast, Token[] token, E

// Groups rules by AstType and Tokens.
Dictionary<string, List<ExternalRule>> astRuleGroups = rules
.Where<ExternalRule>(item => item.GetParameter().EndsWith("ast", true, CultureInfo.CurrentCulture))
.GroupBy<ExternalRule, string>(item => item.GetParameter())
.Where<ExternalRule>(item => item.GetParameter().EndsWith("ast", StringComparison.OrdinalIgnoreCase))
.GroupBy<ExternalRule, string>(item => item.GetParameterType())
.ToDictionary(item => item.Key, item => item.ToList());

Dictionary<string, List<ExternalRule>> tokenRuleGroups = rules
.Where<ExternalRule>(item => item.GetParameter().EndsWith("token", true, CultureInfo.CurrentCulture))
.GroupBy<ExternalRule, string>(item => item.GetParameter())
.Where<ExternalRule>(item => item.GetParameter().EndsWith("token", StringComparison.OrdinalIgnoreCase))
.GroupBy<ExternalRule, string>(item => item.GetParameterType())
.ToDictionary(item => item.Key, item => item.ToList());

using (rsp)
Expand Down Expand Up @@ -337,7 +337,7 @@ public IEnumerable<DiagnosticRecord> GetExternalRecord(Ast ast, Token[] token, E
{
// Find all AstTypes that appeared in rule groups.
IEnumerable<Ast> childAsts = ast.FindAll(new Func<Ast, bool>((testAst) =>
(testAst.GetType().Name.ToLower(CultureInfo.CurrentCulture) == astRuleGroup.Key.ToLower(CultureInfo.CurrentCulture))), false);
(astRuleGroup.Key.IndexOf(testAst.GetType().FullName,StringComparison.OrdinalIgnoreCase) != -1)), false);

foreach (Ast childAst in childAsts)
{
Expand Down Expand Up @@ -365,49 +365,63 @@ public IEnumerable<DiagnosticRecord> GetExternalRecord(Ast ast, Token[] token, E
}

#endregion

#region Collects the results from commands.

for (int i = 0; i < powerShellCommands.Count; i++)
List<DiagnosticRecord> diagnostics = new List<DiagnosticRecord>();
try
{
// EndInvoke will wait for each command to finish, so we will be getting the commands
// in the same order that they have been invoked withy BeginInvoke.
PSDataCollection<PSObject> psobjects = powerShellCommands[i].EndInvoke(powerShellCommandResults[i]);

foreach (var psobject in psobjects)
for (int i = 0; i < powerShellCommands.Count; i++)
{
DiagnosticSeverity severity;
IScriptExtent extent;
string message = string.Empty;
string ruleName = string.Empty;

// Because error stream is merged to output stream,
// we need to handle the error records.
if (psobject.ImmediateBaseObject is ErrorRecord)
{
ErrorRecord record = (ErrorRecord)psobject.ImmediateBaseObject;
command.WriteError(record);
continue;
}
// EndInvoke will wait for each command to finish, so we will be getting the commands
// in the same order that they have been invoked withy BeginInvoke.
PSDataCollection<PSObject> psobjects = powerShellCommands[i].EndInvoke(powerShellCommandResults[i]);

// DiagnosticRecord may not be correctly returned from external rule.
try
foreach (var psobject in psobjects)
{
Enum.TryParse<DiagnosticSeverity>(psobject.Properties["Severity"].Value.ToString().ToUpper(), out severity);
message = psobject.Properties["Message"].Value.ToString();
extent = (IScriptExtent)psobject.Properties["Extent"].Value;
ruleName = psobject.Properties["RuleName"].Value.ToString();
DiagnosticSeverity severity;
IScriptExtent extent;
string message = string.Empty;
string ruleName = string.Empty;

if (psobject != null && psobject.ImmediateBaseObject != null)
{
// Because error stream is merged to output stream,
// we need to handle the error records.
if (psobject.ImmediateBaseObject is ErrorRecord)
{
ErrorRecord record = (ErrorRecord)psobject.ImmediateBaseObject;
command.WriteError(record);
continue;
}

// DiagnosticRecord may not be correctly returned from external rule.
try
{
Enum.TryParse<DiagnosticSeverity>(psobject.Properties["Severity"].Value.ToString().ToUpper(), out severity);
message = psobject.Properties["Message"].Value.ToString();
extent = (IScriptExtent)psobject.Properties["Extent"].Value;
ruleName = psobject.Properties["RuleName"].Value.ToString();
}
catch (Exception ex)
{
command.WriteError(new ErrorRecord(ex, ex.HResult.ToString("X"), ErrorCategory.NotSpecified, this));
continue;
}

if (!string.IsNullOrEmpty(message))
{
diagnostics.Add(new DiagnosticRecord(message, extent, ruleName, severity, null));
}
}
}
catch (Exception ex)
{
command.WriteError(new ErrorRecord(ex, ex.HResult.ToString("X"), ErrorCategory.NotSpecified, this));
continue;
}

if (!string.IsNullOrEmpty(message)) yield return new DiagnosticRecord(message, extent, ruleName, severity, null);
}
}
//Catch exception where customized defined rules have exceptins when doing invoke
catch(Exception ex)
{
command.WriteError(new ErrorRecord(ex, ex.HResult.ToString("X"), ErrorCategory.NotSpecified, this));
}

return diagnostics;
#endregion
}
}
Expand Down Expand Up @@ -478,7 +492,7 @@ public Dictionary<string, List<string>> CheckRuleExtension(string[] path, PSCmdl

cmdlet.WriteDebug(string.Format(CultureInfo.CurrentCulture, Strings.CheckAssemblyFile, resolvedPath));

if (Path.GetExtension(resolvedPath).ToLower(CultureInfo.CurrentCulture) == ".dll")
if (String.Equals(Path.GetExtension(resolvedPath),".dll", StringComparison.OrdinalIgnoreCase))
{
if (!File.Exists(resolvedPath))
{
Expand Down
26 changes: 26 additions & 0 deletions RuleDocumentation/AvoidUsingWMICmdlet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#AvoidUsingWMICmdlet
**Severity Level: Warning**


##Description

Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance

For PowerShell 3.0 and above, use CIM cmdlet which perform the same tasks as the WMI cmdlets. The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, which enables the cmdlets to use the same techniques to manage Windows computers and those running other operating systems.

##How to Fix

Use corresponding CIM cmdlets such as Get-CIMInstance, Remove-CIMInstance, Invoke-CIMMethod, Register-CimIndicationEvent, Set-CimInstance

##Example

Wrong:
```
Get-WmiObject -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-WmiObject
Invoke-WmiMethod –Class Win32_Process –Name "Create" –ArgumentList @{ CommandLine = "notepad.exe" }
```
Correct:
```
Get-CimInstance -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-CIMInstance
Invoke-CimMethod –ClassName Win32_Process –MethodName "Create" –Arguments @{ CommandLine = "notepad.exe" }
```
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@
namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules
{
/// <summary>
/// AvoidUsingWMIObjectCmdlet: Verify that Get-WMIObject, Remove-WMIObject are not used
/// AvoidUsingWMICmdlet: Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance
/// </summary>
[Export(typeof(IScriptRule))]
public class AvoidUsingWMIObjectCmdlet : IScriptRule
public class AvoidUsingWMICmdlet : IScriptRule
{
/// <summary>
/// AnalyzeScript: Verify that Get-WMIObject, Remove-WMIObject are not used
/// AnalyzeScript: Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance
/// </summary>
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
{
if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);

// Rule is applicable only when PowerShell Version is < 3.0, since Get-CIMInstance was introduced in 3.0
// Rule is applicable only when PowerShell Version is < 3.0, since CIM cmdlet was introduced in 3.0
int majorPSVersion = GetPSMajorVersion(ast);
if (!(3 > majorPSVersion && 0 < majorPSVersion))
{
Expand All @@ -50,9 +50,15 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
// Iterate all CommandAsts and check the command name
foreach (CommandAst cmdAst in commandAsts)
{
if (cmdAst.GetCommandName() != null && (String.Equals(cmdAst.GetCommandName(), "get-wmiobject", StringComparison.OrdinalIgnoreCase) || String.Equals(cmdAst.GetCommandName(), "remove-wmiobject", StringComparison.OrdinalIgnoreCase)))
if (cmdAst.GetCommandName() != null &&
(String.Equals(cmdAst.GetCommandName(), "get-wmiobject", StringComparison.OrdinalIgnoreCase)
|| String.Equals(cmdAst.GetCommandName(), "remove-wmiobject", StringComparison.OrdinalIgnoreCase)
|| String.Equals(cmdAst.GetCommandName(), "invoke-wmimethod", StringComparison.OrdinalIgnoreCase)
|| String.Equals(cmdAst.GetCommandName(), "register-wmievent", StringComparison.OrdinalIgnoreCase)
|| String.Equals(cmdAst.GetCommandName(), "set-wmiinstance", StringComparison.OrdinalIgnoreCase))
)
{
yield return new DiagnosticRecord(String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMIObjectCmdletError, System.IO.Path.GetFileName(fileName)),
yield return new DiagnosticRecord(String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletError, System.IO.Path.GetFileName(fileName)),
cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
}
}
Expand Down Expand Up @@ -87,7 +93,7 @@ private int GetPSMajorVersion(Ast ast)
/// <returns>The name of this rule</returns>
public string GetName()
{
return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingWMIObjectCmdletName);
return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingWMICmdletName);
}

/// <summary>
Expand All @@ -96,7 +102,7 @@ public string GetName()
/// <returns>The common name of this rule</returns>
public string GetCommonName()
{
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMIObjectCmdletCommonName);
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletCommonName);
}

/// <summary>
Expand All @@ -105,7 +111,7 @@ public string GetCommonName()
/// <returns>The description of this rule</returns>
public string GetDescription()
{
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMIObjectCmdletDescription);
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletDescription);
}

/// <summary>
Expand Down
Loading