Skip to content

Commit 6cb8120

Browse files
committed
Updated existing rule for verifiying the presence of WMI cmdlets in a script - new WMI cmdlets covered
1 parent ff75584 commit 6cb8120

File tree

3 files changed

+153
-9
lines changed

3 files changed

+153
-9
lines changed

Rules/AvoidUsingWMICmdlet.cs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//
2+
// Copyright (c) Microsoft Corporation.
3+
//
4+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
9+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
10+
// THE SOFTWARE.
11+
//
12+
13+
using System;
14+
using System.Collections.ObjectModel;
15+
using System.Collections.Generic;
16+
using System.Linq;
17+
using System.Text;
18+
using System.Threading.Tasks;
19+
using System.Management.Automation;
20+
using System.Management.Automation.Language;
21+
using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic;
22+
using System.ComponentModel.Composition;
23+
using System.Resources;
24+
using System.Globalization;
25+
using System.Threading;
26+
using System.Reflection;
27+
28+
namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules
29+
{
30+
/// <summary>
31+
/// AvoidUsingWMICmdlet: Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance
32+
/// </summary>
33+
[Export(typeof(IScriptRule))]
34+
public class AvoidUsingWMICmdlet : IScriptRule
35+
{
36+
/// <summary>
37+
/// AnalyzeScript: Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance
38+
/// </summary>
39+
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
40+
{
41+
if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
42+
43+
// Rule is applicable only when PowerShell Version is < 3.0, since CIM cmdlet was introduced in 3.0
44+
int majorPSVersion = GetPSMajorVersion(ast);
45+
if (!(3 > majorPSVersion && 0 < majorPSVersion))
46+
{
47+
// Finds all CommandAsts.
48+
IEnumerable<Ast> commandAsts = ast.FindAll(testAst => testAst is CommandAst, true);
49+
50+
// Iterate all CommandAsts and check the command name
51+
foreach (CommandAst cmdAst in commandAsts)
52+
{
53+
if (cmdAst.GetCommandName() != null &&
54+
(String.Equals(cmdAst.GetCommandName(), "get-wmiobject", StringComparison.OrdinalIgnoreCase)
55+
|| String.Equals(cmdAst.GetCommandName(), "remove-wmiobject", StringComparison.OrdinalIgnoreCase)
56+
|| String.Equals(cmdAst.GetCommandName(), "invoke-wmimethod", StringComparison.OrdinalIgnoreCase)
57+
|| String.Equals(cmdAst.GetCommandName(), "register-wmievent", StringComparison.OrdinalIgnoreCase)
58+
|| String.Equals(cmdAst.GetCommandName(), "set-wmiinstance", StringComparison.OrdinalIgnoreCase))
59+
)
60+
{
61+
yield return new DiagnosticRecord(String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletError, System.IO.Path.GetFileName(fileName)),
62+
cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
63+
}
64+
}
65+
}
66+
}
67+
68+
/// <summary>
69+
/// GetPSMajorVersion: Retrieves Major PowerShell Version when supplied using #requires keyword in the script
70+
/// </summary>
71+
/// <returns>The name of this rule</returns>
72+
private int GetPSMajorVersion(Ast ast)
73+
{
74+
if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
75+
76+
IEnumerable<Ast> scriptBlockAsts = ast.FindAll(testAst => testAst is ScriptBlockAst, true);
77+
78+
foreach (ScriptBlockAst scriptBlockAst in scriptBlockAsts)
79+
{
80+
if (null != scriptBlockAst.ScriptRequirements && null != scriptBlockAst.ScriptRequirements.RequiredPSVersion)
81+
{
82+
return scriptBlockAst.ScriptRequirements.RequiredPSVersion.Major;
83+
}
84+
}
85+
86+
// return a non valid Major version if #requires -Version is not supplied in the Script
87+
return -1;
88+
}
89+
90+
/// <summary>
91+
/// GetName: Retrieves the name of this rule.
92+
/// </summary>
93+
/// <returns>The name of this rule</returns>
94+
public string GetName()
95+
{
96+
return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingWMICmdletName);
97+
}
98+
99+
/// <summary>
100+
/// GetCommonName: Retrieves the common name of this rule.
101+
/// </summary>
102+
/// <returns>The common name of this rule</returns>
103+
public string GetCommonName()
104+
{
105+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletCommonName);
106+
}
107+
108+
/// <summary>
109+
/// GetDescription: Retrieves the description of this rule.
110+
/// </summary>
111+
/// <returns>The description of this rule</returns>
112+
public string GetDescription()
113+
{
114+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMICmdletDescription);
115+
}
116+
117+
/// <summary>
118+
/// GetSourceType: Retrieves the type of the rule: builtin, managed or module.
119+
/// </summary>
120+
public SourceType GetSourceType()
121+
{
122+
return SourceType.Builtin;
123+
}
124+
125+
126+
/// <summary>
127+
/// GetSeverity:Retrieves the severity of the rule: error, warning of information.
128+
/// </summary>
129+
/// <returns></returns>
130+
public RuleSeverity GetSeverity()
131+
{
132+
return RuleSeverity.Warning;
133+
}
134+
135+
136+
/// <summary>
137+
/// GetSourceName: Retrieves the module/assembly name the rule is from.
138+
/// </summary>
139+
public string GetSourceName()
140+
{
141+
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
142+
}
143+
}
144+
}

Rules/ScriptAnalyzerBuiltinRules.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
<Compile Include="AvoidUsingInternalURLs.cs" />
6767
<Compile Include="AvoidUsingInvokeExpression.cs" />
6868
<Compile Include="AvoidUsingPlainTextForPassword.cs" />
69-
<Compile Include="AvoidUsingWMIObjectCmdlet.cs" />
69+
<Compile Include="AvoidUsingWMICmdlet.cs" />
7070
<Compile Include="AvoidUsingWriteHost.cs" />
7171
<Compile Include="MissingModuleManifestField.cs" />
7272
<Compile Include="PossibleIncorrectComparisonWithNull.cs" />

Rules/Strings.resx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -666,16 +666,16 @@
666666
<data name="UseShouldProcessForStateChangingFunctionsName" xml:space="preserve">
667667
<value>UseShouldProcessForStateChangingFunctions</value>
668668
</data>
669-
<data name="AvoidUsingWMIObjectCmdletCommonName" xml:space="preserve">
670-
<value>Avoid Using Get-WMIObject, Remove-WMIObject</value>
669+
<data name="AvoidUsingWMICmdletCommonName" xml:space="preserve">
670+
<value>Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance</value>
671671
</data>
672-
<data name="AvoidUsingWMIObjectCmdletDescription" xml:space="preserve">
673-
<value>Depricated. Starting in Windows PowerShell 3.0, these cmdlets have been superseded by CimInstance cmdlets.</value>
672+
<data name="AvoidUsingWMICmdletDescription" xml:space="preserve">
673+
<value>Depricated. Starting in Windows PowerShell 3.0, these cmdlets have been superseded by CIM cmdlets.</value>
674674
</data>
675-
<data name="AvoidUsingWMIObjectCmdletError" xml:space="preserve">
676-
<value>File '{0}' uses WMIObject cmdlet. For PowerShell 3.0 and above, this is not recommended because the cmdlet is based on a non-standard DCOM protocol. Use CIMInstance cmdlet instead. This is CIM and WS-Man standards compliant and works in a heterogeneous environment.</value>
675+
<data name="AvoidUsingWMICmdletError" xml:space="preserve">
676+
<value>File '{0}' uses WMI cmdlet. 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.</value>
677677
</data>
678-
<data name="AvoidUsingWMIObjectCmdletName" xml:space="preserve">
679-
<value>AvoidUsingWMIObjectCmdlet</value>
678+
<data name="AvoidUsingWMICmdletName" xml:space="preserve">
679+
<value>AvoidUsingWMICmdlet</value>
680680
</data>
681681
</root>

0 commit comments

Comments
 (0)