diff --git a/Engine/Commands/GetScriptAnalyzerRuleCommand.cs b/Engine/Commands/GetScriptAnalyzerRuleCommand.cs index 21883302e..6ba2003ea 100644 --- a/Engine/Commands/GetScriptAnalyzerRuleCommand.cs +++ b/Engine/Commands/GetScriptAnalyzerRuleCommand.cs @@ -10,17 +10,14 @@ // THE SOFTWARE. // +using Microsoft.PowerShell.Commands; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System; using System.Collections.Generic; -using System.ComponentModel.Composition; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Management.Automation; -using System.Resources; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Commands { @@ -50,12 +47,27 @@ public string[] CustomizedRulePath [Parameter(Mandatory = false)] [ValidateNotNullOrEmpty] [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public string[] Name + public string[] RuleName { get { return name; } set { name = value; } } private string[] name; + + /// + /// Severity: Array of the severity types to be enabled. + /// + /// + [ValidateSet("Warning", "Error", "Information", IgnoreCase = true)] + [Parameter(Mandatory = false)] + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] + public string[] Severity + { + get { return severity; } + set { severity = value; } + } + private string[] severity; + #endregion Parameters #region Private Members @@ -128,9 +140,16 @@ protected override void ProcessRecord() } else { + if (severity != null) + { + var ruleSeverity = severity.Select(item => Enum.Parse(typeof (RuleSeverity), item)); + rules = rules.Where(item => ruleSeverity.Contains(item.GetSeverity())).ToList(); + } + foreach (IRule rule in rules) { - WriteObject(new RuleInfo(rule.GetName(), rule.GetCommonName(), rule.GetDescription(), rule.GetSourceType(), rule.GetSourceName())); + WriteObject(new RuleInfo(rule.GetName(), rule.GetCommonName(), rule.GetDescription(), + rule.GetSourceType(), rule.GetSourceName(), rule.GetSeverity())); } } } diff --git a/Engine/Commands/InvokeScriptAnalyzerCommand.cs b/Engine/Commands/InvokeScriptAnalyzerCommand.cs index cd04f621e..fb1272d04 100644 --- a/Engine/Commands/InvokeScriptAnalyzerCommand.cs +++ b/Engine/Commands/InvokeScriptAnalyzerCommand.cs @@ -10,6 +10,7 @@ // THE SOFTWARE. // +using System.Text.RegularExpressions; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System; using System.Collections.Generic; @@ -272,7 +273,28 @@ private void AnalyzeFile(string filePath) IEnumerable funcDefAsts; // Use a List of KVP rather than dictionary, since for a script containing inline functions with same signature, keys clash - List> cmdInfoTable = new List>(); + List> cmdInfoTable = new List>(); + + //Check wild card input for the Include/ExcludeRules and create regex match patterns + List includeRegexList = new List(); + List excludeRegexList = new List(); + if (includeRule != null) + { + foreach (string rule in includeRule) + { + Regex includeRegex = new Regex(String.Format("^{0}$", Regex.Escape(rule).Replace(@"\*", ".*")), RegexOptions.IgnoreCase); + includeRegexList.Add(includeRegex); + } + } + if (excludeRule != null) + { + foreach (string rule in excludeRule) + { + Regex excludeRegex = new Regex(String.Format("^{0}$", Regex.Escape(rule).Replace(@"\*", ".*")), RegexOptions.IgnoreCase); + excludeRegexList.Add(excludeRegex); + } + } + //Parse the file if (File.Exists(filePath)) @@ -316,12 +338,30 @@ private void AnalyzeFile(string filePath) #region Run ScriptRules //Trim down to the leaf element of the filePath and pass it to Diagnostic Record string fileName = System.IO.Path.GetFileName(filePath); + if (ScriptAnalyzer.Instance.ScriptRules != null) { foreach (IScriptRule scriptRule in ScriptAnalyzer.Instance.ScriptRules) { - if ((includeRule == null || includeRule.Contains(scriptRule.GetName(), StringComparer.OrdinalIgnoreCase)) && - (excludeRule == null || !excludeRule.Contains(scriptRule.GetName(), StringComparer.OrdinalIgnoreCase))) + bool includeRegexMatch = false; + bool excludeRegexMatch = false; + foreach (Regex include in includeRegexList) + { + if (include.IsMatch(scriptRule.GetName())) + { + includeRegexMatch = true; + break; + } + } + foreach (Regex exclude in excludeRegexList) + { + if (exclude.IsMatch(scriptRule.GetName())) + { + excludeRegexMatch = true; + break; + } + } + if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch)) { WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, scriptRule.GetName())); @@ -334,7 +374,6 @@ private void AnalyzeFile(string filePath) catch (Exception scriptRuleException) { WriteError(new ErrorRecord(scriptRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath)); - continue; } } } @@ -379,8 +418,25 @@ private void AnalyzeFile(string filePath) { foreach (ICommandRule commandRule in ScriptAnalyzer.Instance.CommandRules) { - if ((includeRule == null || includeRule.Contains(commandRule.GetName(), StringComparer.OrdinalIgnoreCase)) && - (excludeRule == null || !excludeRule.Contains(commandRule.GetName(), StringComparer.OrdinalIgnoreCase))) + bool includeRegexMatch = false; + bool excludeRegexMatch = false; + foreach (Regex include in includeRegexList) + { + if (include.IsMatch(commandRule.GetName())) + { + includeRegexMatch = true; + break; + } + } + foreach (Regex exclude in excludeRegexList) + { + if (exclude.IsMatch(commandRule.GetName())) + { + excludeRegexMatch = true; + break; + } + } + if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch)) { foreach (KeyValuePair commandInfo in cmdInfoTable) { @@ -395,7 +451,6 @@ private void AnalyzeFile(string filePath) catch (Exception commandRuleException) { WriteError(new ErrorRecord(commandRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName)); - continue; } } } @@ -410,8 +465,25 @@ private void AnalyzeFile(string filePath) { foreach (ITokenRule tokenRule in ScriptAnalyzer.Instance.TokenRules) { - if ((includeRule == null || includeRule.Contains(tokenRule.GetName(), StringComparer.OrdinalIgnoreCase)) && - (excludeRule == null || !excludeRule.Contains(tokenRule.GetName(), StringComparer.OrdinalIgnoreCase))) + bool includeRegexMatch = false; + bool excludeRegexMatch = false; + foreach (Regex include in includeRegexList) + { + if (include.IsMatch(tokenRule.GetName())) + { + includeRegexMatch = true; + break; + } + } + foreach (Regex exclude in excludeRegexList) + { + if (exclude.IsMatch(tokenRule.GetName())) + { + excludeRegexMatch = true; + break; + } + } + if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch)) { WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, tokenRule.GetName())); @@ -424,7 +496,6 @@ private void AnalyzeFile(string filePath) catch (Exception tokenRuleException) { WriteError(new ErrorRecord(tokenRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, fileName)); - continue; } } } @@ -438,8 +509,25 @@ private void AnalyzeFile(string filePath) // Run DSC Class rule foreach (IDSCResourceRule dscResourceRule in ScriptAnalyzer.Instance.DSCResourceRules) { - if ((includeRule == null || includeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase)) && - (excludeRule == null || !excludeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase))) + bool includeRegexMatch = false; + bool excludeRegexMatch = false; + foreach (Regex include in includeRegexList) + { + if (include.IsMatch(dscResourceRule.GetName())) + { + includeRegexMatch = true; + break; + } + } + foreach (Regex exclude in excludeRegexList) + { + if (exclude.IsMatch(dscResourceRule.GetName())) + { + excludeRegexMatch = true; + break; + } + } + if ((includeRule == null || includeRegexMatch) && (excludeRule == null || excludeRegexMatch)) { WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, dscResourceRule.GetName())); @@ -452,7 +540,6 @@ private void AnalyzeFile(string filePath) catch (Exception dscResourceRuleException) { WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath)); - continue; } } } @@ -480,8 +567,24 @@ private void AnalyzeFile(string filePath) // Run all DSC Rules foreach (IDSCResourceRule dscResourceRule in ScriptAnalyzer.Instance.DSCResourceRules) { - if ((includeRule == null || includeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase)) && - (excludeRule == null || !excludeRule.Contains(dscResourceRule.GetName(), StringComparer.OrdinalIgnoreCase))) + bool includeRegexMatch = false; + bool excludeRegexMatch = false; + foreach (Regex include in includeRegexList) + { + if (include.IsMatch(dscResourceRule.GetName())) + { + includeRegexMatch = true; + break; + } + } + foreach (Regex exclude in excludeRegexList) + { + if (exclude.IsMatch(dscResourceRule.GetName())) + { + excludeRegexMatch = true; + } + } + if ((includeRule == null || includeRegexMatch) && (excludeRule == null || !excludeRegexMatch)) { WriteVerbose(string.Format(CultureInfo.CurrentCulture, Strings.VerboseRunningMessage, dscResourceRule.GetName())); @@ -494,7 +597,6 @@ private void AnalyzeFile(string filePath) catch (Exception dscResourceRuleException) { WriteError(new ErrorRecord(dscResourceRuleException, Strings.RuleError, ErrorCategory.InvalidOperation, filePath)); - continue; } } } diff --git a/Engine/Generic/AvoidCmdletGeneric.cs b/Engine/Generic/AvoidCmdletGeneric.cs index 7946f7895..1ae87fa31 100644 --- a/Engine/Generic/AvoidCmdletGeneric.cs +++ b/Engine/Generic/AvoidCmdletGeneric.cs @@ -93,5 +93,11 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) /// /// The source type of the rule. public abstract SourceType GetSourceType(); + + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public abstract RuleSeverity GetSeverity(); } } diff --git a/Engine/Generic/AvoidParameterGeneric.cs b/Engine/Generic/AvoidParameterGeneric.cs index 7f6a0bf96..89eb433fc 100644 --- a/Engine/Generic/AvoidParameterGeneric.cs +++ b/Engine/Generic/AvoidParameterGeneric.cs @@ -104,5 +104,7 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) /// /// The source type of the rule. public abstract SourceType GetSourceType(); + + public abstract RuleSeverity GetSeverity(); } } diff --git a/Engine/Generic/ExternalRule.cs b/Engine/Generic/ExternalRule.cs index 43b849401..934bbc831 100644 --- a/Engine/Generic/ExternalRule.cs +++ b/Engine/Generic/ExternalRule.cs @@ -55,6 +55,12 @@ public SourceType GetSourceType() return SourceType.Module; } + //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() + { + return RuleSeverity.Warning; + } + public string GetSourceName() { return this.srcName; diff --git a/Engine/Generic/IRule.cs b/Engine/Generic/IRule.cs index e4c3f3bc6..e9ddbbf8e 100644 --- a/Engine/Generic/IRule.cs +++ b/Engine/Generic/IRule.cs @@ -10,12 +10,6 @@ // THE SOFTWARE. // -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Generic { /// @@ -52,5 +46,12 @@ public interface IRule /// /// The source type of the rule. SourceType GetSourceType(); + + /// + /// GetSeverity: Retrieves severity of the rule. + /// + /// + RuleSeverity GetSeverity(); + } } diff --git a/Engine/Generic/RuleInfo.cs b/Engine/Generic/RuleInfo.cs index 1848599e5..666c84afa 100644 --- a/Engine/Generic/RuleInfo.cs +++ b/Engine/Generic/RuleInfo.cs @@ -29,12 +29,13 @@ public class RuleInfo private string description; private SourceType sourceType; private string sourceName; + private RuleSeverity ruleSeverity; /// /// Name: The name of the rule. /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public string Name + public string RuleName { get { return name; } private set { name = value; } @@ -81,6 +82,16 @@ public string SourceName private set { sourceName = value; } } + /// + /// Severity : The severity of the rule violation. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public RuleSeverity Severity + { + get { return ruleSeverity; } + private set { ruleSeverity = value; } + } + /// /// Constructor for a RuleInfo. /// @@ -89,13 +100,14 @@ public string SourceName /// Description of the rule. /// Source type of the rule. /// Source name of the rule. - public RuleInfo(string name, string commonName, string description, SourceType sourceType, string sourceName) + public RuleInfo(string name, string commonName, string description, SourceType sourceType, string sourceName, RuleSeverity severity) { - Name = name; + RuleName = name; CommonName = commonName; Description = description; SourceType = sourceType; SourceName = sourceName; + Severity = severity; } } } diff --git a/Engine/Generic/RuleSeverity.cs b/Engine/Generic/RuleSeverity.cs new file mode 100644 index 000000000..75496ed43 --- /dev/null +++ b/Engine/Generic/RuleSeverity.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft Corporation. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Generic +{ + /// + /// Represents the severity of a PSScriptAnalyzer rule + /// + public enum RuleSeverity : uint + { + /// + /// Information: This warning is trivial, but may be useful. They are recommended by PowerShell best practice. + /// + Information = 0, + + /// + /// WARNING: This warning may cause a problem or does not follow PowerShell's recommended guidelines. + /// + Warning = 1, + + /// + /// ERROR: This warning is likely to cause a problem or does not follow PowerShell's required guidelines. + /// + Error = 2, + }; +} diff --git a/Engine/Generic/SkipTypeDefinition.cs b/Engine/Generic/SkipTypeDefinition.cs index 25214c50f..c95d772fe 100644 --- a/Engine/Generic/SkipTypeDefinition.cs +++ b/Engine/Generic/SkipTypeDefinition.cs @@ -16,9 +16,9 @@ namespace Microsoft.Windows.Powershell.ScriptAnalyzer.Generic { /// - /// This class extends AstVisitor2 and will skip any typedefinitionast + /// This class extends AstVisitor and will skip any typedefinitionast /// - public class SkipTypeDefinition : AstVisitor2 + public class SkipTypeDefinition : AstVisitor { /// /// File name @@ -30,14 +30,5 @@ public class SkipTypeDefinition : AstVisitor2 /// public List DiagnosticRecords = new List(); - /// - /// Skip typedefinition - /// - /// - /// - public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefAst) - { - return AstVisitAction.SkipChildren; - } } } diff --git a/Engine/Helper.cs b/Engine/Helper.cs index 70bd69f6b..41c0a326a 100644 --- a/Engine/Helper.cs +++ b/Engine/Helper.cs @@ -700,7 +700,8 @@ public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) VariableAnalysis previousOuter = OuterAnalysis; - // We already run variable analysis in these cases so check + // We already run variable analysis if the parent is a function so skip these. + // Otherwise, we have to do variable analysis using the outer scope variables. if (!(scriptBlockAst.Parent is FunctionDefinitionAst) && !(scriptBlockAst.Parent is FunctionMemberAst)) { OuterAnalysis = Helper.Instance.InitializeVariableAnalysisHelper(scriptBlockAst, OuterAnalysis); @@ -726,8 +727,15 @@ public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) scriptBlockAst.EndBlock.Visit(this); } + VariableAnalysis innerAnalysis = OuterAnalysis; OuterAnalysis = previousOuter; + if (!(scriptBlockAst.Parent is FunctionDefinitionAst) && !(scriptBlockAst.Parent is FunctionMemberAst)) + { + // Update the variable analysis of the outer script block + VariableAnalysis.UpdateOuterAnalysis(OuterAnalysis, innerAnalysis); + } + return null; } @@ -889,6 +897,13 @@ public object VisitCatchClause(CatchClauseAst catchClauseAst) /// public object VisitCommand(CommandAst commandAst) { + if (commandAst == null) return null; + + foreach (CommandElementAst ceAst in commandAst.CommandElements) + { + ceAst.Visit(this); + } + return null; } @@ -1219,12 +1234,19 @@ public object VisitParenExpression(ParenExpressionAst parenExpressionAst) } /// - /// Do nothing + /// Visit pipeline /// /// /// public object VisitPipeline(PipelineAst pipelineAst) { + if (pipelineAst == null) return null; + + foreach (var command in pipelineAst.PipelineElements) + { + command.Visit(this); + } + return null; } diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs index 1dacd3d63..5f995abce 100644 --- a/Engine/ScriptAnalyzer.cs +++ b/Engine/ScriptAnalyzer.cs @@ -33,7 +33,6 @@ internal class ScriptAnalyzer #region Private memebers private CompositionContainer container; - private const string baseName = "Microsoft.Windows.Powershell.ScriptAnalyzer.Properties.Strings"; #endregion @@ -91,7 +90,7 @@ public static ScriptAnalyzer Instance public void Initialize() { // Clear external rules for each invoke. - this.ExternalRules = new List(); + ExternalRules = new List(); // Initialize helper Helper.Instance.Initialize(); @@ -129,7 +128,7 @@ public void Initilaize(Dictionary> result) List paths = new List(); // Clear external rules for each invoke. - this.ExternalRules = new List(); + ExternalRules = new List(); // Initialize helper Helper.Instance.Initialize(); diff --git a/Engine/ScriptAnalyzer.format.ps1xml b/Engine/ScriptAnalyzer.format.ps1xml index d13b8f71c..188b73ecc 100644 --- a/Engine/ScriptAnalyzer.format.ps1xml +++ b/Engine/ScriptAnalyzer.format.ps1xml @@ -10,15 +10,15 @@ 35 - + - 10 + 12 10 - + 5 @@ -62,19 +62,19 @@ - 30 - + 35 + - 33 - + 15 + - 45 + 60 - 8 + 10 @@ -83,10 +83,10 @@ - Name + RuleName - CommonName + Severity Description diff --git a/Engine/ScriptAnalyzer.types.ps1xml b/Engine/ScriptAnalyzer.types.ps1xml index 47bf4b417..ded4e0922 100644 --- a/Engine/ScriptAnalyzer.types.ps1xml +++ b/Engine/ScriptAnalyzer.types.ps1xml @@ -41,8 +41,8 @@ DefaultDisplayPropertySet - Name - CommonName + RuleName + Severity Description SourceName diff --git a/Engine/ScriptAnalyzerEngine.csproj b/Engine/ScriptAnalyzerEngine.csproj index 990354497..169da7260 100644 --- a/Engine/ScriptAnalyzerEngine.csproj +++ b/Engine/ScriptAnalyzerEngine.csproj @@ -1,4 +1,4 @@ - + Debug @@ -63,6 +63,7 @@ + @@ -99,4 +100,4 @@ copy /y "$(ProjectDir)\*.ps1xml" "$(SolutionDir)$(SolutionName)" copy /y "$(ProjectDir)\*.psd1" "$(SolutionDir)$(SolutionName)" copy /y "$(TargetPath)" "$(SolutionDir)$(SolutionName)" - + \ No newline at end of file diff --git a/Engine/VariableAnalysis.cs b/Engine/VariableAnalysis.cs index bbfa309cf..352ab40ef 100644 --- a/Engine/VariableAnalysis.cs +++ b/Engine/VariableAnalysis.cs @@ -255,6 +255,31 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) } } + /// + /// Updates the variablesdictionary of the outeranalysis based on that of the inneranalysis + /// + /// + /// + internal static void UpdateOuterAnalysis(VariableAnalysis OuterAnalysis, VariableAnalysis InnerAnalysis) + { + if (OuterAnalysis == null || InnerAnalysis == null) + { + return; + } + + foreach (var key in InnerAnalysis.VariablesDictionary.Keys) + { + if (OuterAnalysis.VariablesDictionary.ContainsKey(key)) + { + OuterAnalysis.VariablesDictionary[key] = InnerAnalysis.VariablesDictionary[key]; + } + else + { + OuterAnalysis.VariablesDictionary.Add(key, InnerAnalysis.VariablesDictionary[key]); + } + } + } + /// /// Return variableanalysisdetails for VarTarget. /// This function should only be called after Block.SparseSimpleConstants are called. diff --git a/Engine/VariableAnalysisBase.cs b/Engine/VariableAnalysisBase.cs index 5f136b99b..17e7cc6c8 100644 --- a/Engine/VariableAnalysisBase.cs +++ b/Engine/VariableAnalysisBase.cs @@ -2957,10 +2957,6 @@ public object VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExp { // Don't recurse into the script block, it's variables are distinct from the script block // we're currently analyzing. - if (scriptBlockExpressionAst != null) - { - scriptBlockExpressionAst.ScriptBlock.Visit(this.Decorator); - } return null; } diff --git a/README.md b/README.md index a45d0f7e4..97fc1146e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ PSScriptAnalyzer is shipped with a collection of built-in rules that checks vari PSScriptAnalyzer cmdlets ====================== ``` -Get-ScriptAnalyzerRule [-CustomizedRulePath ] [-Name ] [] +Get-ScriptAnalyzerRule [-CustomizedRulePath ] [-Name ] [] [-Severity ] Invoke-ScriptAnalyzer [-Path] [-CustomizedRulePath ] [-ExcludeRule ] [-IncludeRule ] [-Severity ] [-Recurse] [] ``` @@ -46,6 +46,7 @@ Pester-based ScriptAnalyzer Tests are located in ```/PSScriptAnalyzer/Te .\InvokeScriptAnalyzer.tests.ps1 * Run Tests for Built-in rules: .\*.ps1 (Example - .\ AvoidConvertToSecureStringWithPlainText.ps1) +*You can also run all tests under \Engine or \Rules by calling Invoke-Pester in the Engine/Rules directory. Contributing to ScriptAnalyzer diff --git a/Rules/AvoidAlias.cs b/Rules/AvoidAlias.cs index 3d012e782..76c963e5c 100644 --- a/Rules/AvoidAlias.cs +++ b/Rules/AvoidAlias.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -97,6 +89,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the name of the module/assembly the rule is from. /// diff --git a/Rules/AvoidDefaultTrueValueSwitchParameter.cs b/Rules/AvoidDefaultTrueValueSwitchParameter.cs index 29feba72f..de4a44637 100644 --- a/Rules/AvoidDefaultTrueValueSwitchParameter.cs +++ b/Rules/AvoidDefaultTrueValueSwitchParameter.cs @@ -11,19 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -91,6 +84,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidEmptyCatchBlock.cs b/Rules/AvoidEmptyCatchBlock.cs index 34db3c9c4..1c9c57b76 100644 --- a/Rules/AvoidEmptyCatchBlock.cs +++ b/Rules/AvoidEmptyCatchBlock.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -91,6 +83,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidGlobalVars.cs b/Rules/AvoidGlobalVars.cs index b7f983854..9158beb62 100644 --- a/Rules/AvoidGlobalVars.cs +++ b/Rules/AvoidGlobalVars.cs @@ -12,16 +12,10 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -93,6 +87,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidInvokingEmptyMembers.cs b/Rules/AvoidInvokingEmptyMembers.cs index 5331b67ca..562f335fd 100644 --- a/Rules/AvoidInvokingEmptyMembers.cs +++ b/Rules/AvoidInvokingEmptyMembers.cs @@ -11,19 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -105,6 +98,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the name of the module/assembly the rule is from. /// diff --git a/Rules/AvoidPositionalParameters.cs b/Rules/AvoidPositionalParameters.cs index db39e021f..cc82105ab 100644 --- a/Rules/AvoidPositionalParameters.cs +++ b/Rules/AvoidPositionalParameters.cs @@ -11,20 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; -using Microsoft.Windows.Powershell.ScriptAnalyzer; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -97,6 +88,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidReservedCharInCmdlet.cs b/Rules/AvoidReservedCharInCmdlet.cs index 0a1ad4a66..c19c0e980 100644 --- a/Rules/AvoidReservedCharInCmdlet.cs +++ b/Rules/AvoidReservedCharInCmdlet.cs @@ -11,19 +11,13 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -85,6 +79,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidReservedParams.cs b/Rules/AvoidReservedParams.cs index 106a37984..b0211f4f9 100644 --- a/Rules/AvoidReservedParams.cs +++ b/Rules/AvoidReservedParams.cs @@ -13,15 +13,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; using System.Management.Automation; using System.Management.Automation.Internal; @@ -106,6 +101,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidShouldContinueWithoutForce.cs b/Rules/AvoidShouldContinueWithoutForce.cs index e6e622d56..ca91b62b0 100644 --- a/Rules/AvoidShouldContinueWithoutForce.cs +++ b/Rules/AvoidShouldContinueWithoutForce.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -119,6 +111,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidTrapStatement.cs b/Rules/AvoidTrapStatement.cs index 5fdd8196a..0dc9b43b1 100644 --- a/Rules/AvoidTrapStatement.cs +++ b/Rules/AvoidTrapStatement.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -89,6 +81,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUnitializedVariable.cs b/Rules/AvoidUnitializedVariable.cs index 337a7d955..8c1a0a440 100644 --- a/Rules/AvoidUnitializedVariable.cs +++ b/Rules/AvoidUnitializedVariable.cs @@ -11,20 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; -using Microsoft.Windows.Powershell.ScriptAnalyzer; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -112,6 +103,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUserNameAndPasswordParams.cs b/Rules/AvoidUserNameAndPasswordParams.cs index c9cceef18..a593b1ae7 100644 --- a/Rules/AvoidUserNameAndPasswordParams.cs +++ b/Rules/AvoidUserNameAndPasswordParams.cs @@ -11,18 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules @@ -129,6 +123,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Error; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUsingComputerNameHardcoded.cs b/Rules/AvoidUsingComputerNameHardcoded.cs index 3563e864a..dab94246a 100644 --- a/Rules/AvoidUsingComputerNameHardcoded.cs +++ b/Rules/AvoidUsingComputerNameHardcoded.cs @@ -11,19 +11,10 @@ // using System; -using System.Collections.ObjectModel; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -131,6 +122,15 @@ public override SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public override RuleSeverity GetSeverity() + { + return RuleSeverity.Error; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUsingConvertToSecureStringWithPlainText.cs b/Rules/AvoidUsingConvertToSecureStringWithPlainText.cs index e7a884b6b..090dcb059 100644 --- a/Rules/AvoidUsingConvertToSecureStringWithPlainText.cs +++ b/Rules/AvoidUsingConvertToSecureStringWithPlainText.cs @@ -11,19 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -44,7 +37,7 @@ public override bool CommandCondition(CommandAst CmdAst) { if (CTSTCmdlet == null) { - CTSTCmdlet = Microsoft.Windows.Powershell.ScriptAnalyzer.Helper.Instance.CmdletNameAndAliases("convertto-securestring"); + CTSTCmdlet = Helper.Instance.CmdletNameAndAliases("convertto-securestring"); } return CmdAst != null && CmdAst.GetCommandName() != null && CTSTCmdlet.Contains(CmdAst.GetCommandName(), StringComparer.OrdinalIgnoreCase); @@ -107,6 +100,15 @@ public override SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public override RuleSeverity GetSeverity() + { + return RuleSeverity.Error; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUsingInternalURLs.cs b/Rules/AvoidUsingInternalURLs.cs index c165d7672..095cd5412 100644 --- a/Rules/AvoidUsingInternalURLs.cs +++ b/Rules/AvoidUsingInternalURLs.cs @@ -13,15 +13,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; using System.IO; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules @@ -119,6 +114,12 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) if (!firstPartURL.Contains(".")) { isInternalURL = true; + //Add a check to exclude potential SDDL format. Check if a string have four components separated by ":" + var count = firstPartURL.Count(x => x == ':'); + if (count == 3 || count == 4 ) + { + isInternalURL = false; + } } } if (isInternalURL) @@ -170,6 +171,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUsingInvokeExpression.cs b/Rules/AvoidUsingInvokeExpression.cs index 99c51f799..81db6dc7a 100644 --- a/Rules/AvoidUsingInvokeExpression.cs +++ b/Rules/AvoidUsingInvokeExpression.cs @@ -11,17 +11,9 @@ // using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -84,6 +76,15 @@ public override SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity:Retrieves the severity of the rule: error, warning of information. + /// + /// + public override RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUsingPlainTextForPassword.cs b/Rules/AvoidUsingPlainTextForPassword.cs index 7933ff47f..a4f6e0d9d 100644 --- a/Rules/AvoidUsingPlainTextForPassword.cs +++ b/Rules/AvoidUsingPlainTextForPassword.cs @@ -11,18 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules @@ -107,6 +100,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/AvoidUsingWMIObjectCmdlet.cs b/Rules/AvoidUsingWMIObjectCmdlet.cs new file mode 100644 index 000000000..6c71f1646 --- /dev/null +++ b/Rules/AvoidUsingWMIObjectCmdlet.cs @@ -0,0 +1,138 @@ +// +// Copyright (c) Microsoft Corporation. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Management.Automation; +using System.Management.Automation.Language; +using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; +using System.ComponentModel.Composition; +using System.Resources; +using System.Globalization; +using System.Threading; +using System.Reflection; + +namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules +{ + /// + /// AvoidUsingWMIObjectCmdlet: Verify that Get-WMIObject, Remove-WMIObject are not used + /// + [Export(typeof(IScriptRule))] + public class AvoidUsingWMIObjectCmdlet : IScriptRule + { + /// + /// AnalyzeScript: Verify that Get-WMIObject, Remove-WMIObject are not used + /// + public IEnumerable 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 + int majorPSVersion = GetPSMajorVersion(ast); + if (!(3 > majorPSVersion && 0 < majorPSVersion)) + { + // Finds all CommandAsts. + IEnumerable commandAsts = ast.FindAll(testAst => testAst is CommandAst, true); + + // 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))) + { + yield return new DiagnosticRecord(String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMIObjectCmdletError, System.IO.Path.GetFileName(fileName)), + cmdAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); + } + } + } + } + + /// + /// GetPSMajorVersion: Retrieves Major PowerShell Version when supplied using #requires keyword in the script + /// + /// The name of this rule + private int GetPSMajorVersion(Ast ast) + { + if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); + + IEnumerable scriptBlockAsts = ast.FindAll(testAst => testAst is ScriptBlockAst, true); + + foreach (ScriptBlockAst scriptBlockAst in scriptBlockAsts) + { + if (null != scriptBlockAst.ScriptRequirements && null != scriptBlockAst.ScriptRequirements.RequiredPSVersion) + { + return scriptBlockAst.ScriptRequirements.RequiredPSVersion.Major; + } + } + + // return a non valid Major version if #requires -Version is not supplied in the Script + return -1; + } + + /// + /// GetName: Retrieves the name of this rule. + /// + /// The name of this rule + public string GetName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingWMIObjectCmdletName); + } + + /// + /// GetCommonName: Retrieves the common name of this rule. + /// + /// The common name of this rule + public string GetCommonName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMIObjectCmdletCommonName); + } + + /// + /// GetDescription: Retrieves the description of this rule. + /// + /// The description of this rule + public string GetDescription() + { + return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingWMIObjectCmdletDescription); + } + + /// + /// GetSourceType: Retrieves the type of the rule: builtin, managed or module. + /// + public SourceType GetSourceType() + { + return SourceType.Builtin; + } + + + /// + /// GetSeverity:Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + + + /// + /// GetSourceName: Retrieves the module/assembly name the rule is from. + /// + public string GetSourceName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); + } + } +} diff --git a/Rules/AvoidUsingWriteHost.cs b/Rules/AvoidUsingWriteHost.cs index b5126a608..597d7cf4a 100644 --- a/Rules/AvoidUsingWriteHost.cs +++ b/Rules/AvoidUsingWriteHost.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -105,6 +97,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/MissingModuleManifestField.cs b/Rules/MissingModuleManifestField.cs index 6816878f3..8caa7e3ff 100644 --- a/Rules/MissingModuleManifestField.cs +++ b/Rules/MissingModuleManifestField.cs @@ -12,18 +12,11 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation.Language; using System.Management.Automation; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; -using System.IO; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -110,6 +103,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/PossibleIncorrectComparisonWithNull.cs b/Rules/PossibleIncorrectComparisonWithNull.cs index 149deebe8..507832322 100644 --- a/Rules/PossibleIncorrectComparisonWithNull.cs +++ b/Rules/PossibleIncorrectComparisonWithNull.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -87,6 +79,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/ProvideCommentHelp.cs b/Rules/ProvideCommentHelp.cs index b6f0e4c02..fbb03b2b9 100644 --- a/Rules/ProvideCommentHelp.cs +++ b/Rules/ProvideCommentHelp.cs @@ -13,15 +13,10 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; using System.Management.Automation; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules @@ -235,6 +230,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Information; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/ProvideVerboseMessage.cs b/Rules/ProvideVerboseMessage.cs index 5f695966d..a69447c0e 100644 --- a/Rules/ProvideVerboseMessage.cs +++ b/Rules/ProvideVerboseMessage.cs @@ -12,16 +12,10 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -117,6 +111,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Information; + } + /// /// Method: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/ReturnCorrectTypesForDSCFunctions.cs b/Rules/ReturnCorrectTypesForDSCFunctions.cs index 3879e8aea..2890660fb 100644 --- a/Rules/ReturnCorrectTypesForDSCFunctions.cs +++ b/Rules/ReturnCorrectTypesForDSCFunctions.cs @@ -11,20 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; -using Microsoft.Windows.Powershell.ScriptAnalyzer; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -217,6 +209,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Information; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/ScriptAnalyzerBuiltinRules.csproj b/Rules/ScriptAnalyzerBuiltinRules.csproj index 9e57fe94f..e85c892d0 100644 --- a/Rules/ScriptAnalyzerBuiltinRules.csproj +++ b/Rules/ScriptAnalyzerBuiltinRules.csproj @@ -66,6 +66,7 @@ + diff --git a/Rules/Strings.Designer.cs b/Rules/Strings.Designer.cs index 7b6c6133a..1ec732308 100644 --- a/Rules/Strings.Designer.cs +++ b/Rules/Strings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.35317 +// Runtime Version:4.0.30319.34014 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -717,6 +717,42 @@ internal static string AvoidUsingPositionalParametersName { } } + /// + /// Looks up a localized string similar to Avoid Using Get-WMIObject, Remove-WMIObject. + /// + internal static string AvoidUsingWMIObjectCmdletCommonName { + get { + return ResourceManager.GetString("AvoidUsingWMIObjectCmdletCommonName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Depricated. Starting in Windows PowerShell 3.0, these cmdlets have been superseded by CimInstance cmdlets.. + /// + internal static string AvoidUsingWMIObjectCmdletDescription { + get { + return ResourceManager.GetString("AvoidUsingWMIObjectCmdletDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 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.. + /// + internal static string AvoidUsingWMIObjectCmdletError { + get { + return ResourceManager.GetString("AvoidUsingWMIObjectCmdletError", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AvoidUsingWMIObjectCmdlet. + /// + internal static string AvoidUsingWMIObjectCmdletName { + get { + return ResourceManager.GetString("AvoidUsingWMIObjectCmdletName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Avoid Using Write-Host. /// diff --git a/Rules/Strings.resx b/Rules/Strings.resx index f8d13de1b..f7501a45c 100644 --- a/Rules/Strings.resx +++ b/Rules/Strings.resx @@ -666,4 +666,16 @@ UseShouldProcessForStateChangingFunctions + + Avoid Using Get-WMIObject, Remove-WMIObject + + + Depricated. Starting in Windows PowerShell 3.0, these cmdlets have been superseded by CimInstance cmdlets. + + + 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. + + + AvoidUsingWMIObjectCmdlet + \ No newline at end of file diff --git a/Rules/UseApprovedVerbs.cs b/Rules/UseApprovedVerbs.cs index 9df853532..e59d57dee 100644 --- a/Rules/UseApprovedVerbs.cs +++ b/Rules/UseApprovedVerbs.cs @@ -11,18 +11,13 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules @@ -102,6 +97,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseCmdletCorrectly.cs b/Rules/UseCmdletCorrectly.cs index f1de7b4cd..a5e854b0b 100644 --- a/Rules/UseCmdletCorrectly.cs +++ b/Rules/UseCmdletCorrectly.cs @@ -11,21 +11,13 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation.Runspaces; using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using Microsoft.Windows.Powershell.ScriptAnalyzer; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -197,6 +189,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseDeclaredVarsMoreThanAssignments.cs b/Rules/UseDeclaredVarsMoreThanAssignments.cs index 6cbd7d883..69e3f0bc3 100644 --- a/Rules/UseDeclaredVarsMoreThanAssignments.cs +++ b/Rules/UseDeclaredVarsMoreThanAssignments.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -95,7 +87,7 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) assignments.Remove(varKey); } //Check if variable belongs to PowerShell builtin variables - if (Microsoft.Windows.Powershell.ScriptAnalyzer.Helper.Instance.HasSpecialVars(varKey)) + if (Helper.Instance.HasSpecialVars(varKey)) { assignments.Remove(varKey); } @@ -144,6 +136,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseIdenticalMandatoryParametersDSC.cs b/Rules/UseIdenticalMandatoryParametersDSC.cs index fb0ac20f4..93309e30d 100644 --- a/Rules/UseIdenticalMandatoryParametersDSC.cs +++ b/Rules/UseIdenticalMandatoryParametersDSC.cs @@ -153,6 +153,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Information; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseIdenticalParametersDSC.cs b/Rules/UseIdenticalParametersDSC.cs index 5f69f6c68..ff33d03c7 100644 --- a/Rules/UseIdenticalParametersDSC.cs +++ b/Rules/UseIdenticalParametersDSC.cs @@ -11,19 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -167,6 +160,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UsePSCredentialType.cs b/Rules/UsePSCredentialType.cs index 070910e2d..a932686d4 100644 --- a/Rules/UsePSCredentialType.cs +++ b/Rules/UsePSCredentialType.cs @@ -11,19 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -126,6 +119,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseShouldProcessCorrectly.cs b/Rules/UseShouldProcessCorrectly.cs index f1cb785e4..de40351cc 100644 --- a/Rules/UseShouldProcessCorrectly.cs +++ b/Rules/UseShouldProcessCorrectly.cs @@ -11,19 +11,11 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -114,6 +106,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseShouldProcessForStateChangingFunctions.cs b/Rules/UseShouldProcessForStateChangingFunctions.cs index cca236a4a..28c50aca4 100644 --- a/Rules/UseShouldProcessForStateChangingFunctions.cs +++ b/Rules/UseShouldProcessForStateChangingFunctions.cs @@ -118,6 +118,16 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseSingularNouns.cs b/Rules/UseSingularNouns.cs index 162a36437..570cadebb 100644 --- a/Rules/UseSingularNouns.cs +++ b/Rules/UseSingularNouns.cs @@ -11,19 +11,13 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -91,6 +85,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Rules/UseStandardDSCFunctionsInResource.cs b/Rules/UseStandardDSCFunctionsInResource.cs index 548eac8fa..60e729cde 100644 --- a/Rules/UseStandardDSCFunctionsInResource.cs +++ b/Rules/UseStandardDSCFunctionsInResource.cs @@ -11,19 +11,12 @@ // using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Management.Automation; using System.Management.Automation.Language; using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; using System.ComponentModel.Composition; -using System.Resources; using System.Globalization; -using System.Threading; -using System.Reflection; namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { @@ -133,6 +126,15 @@ public SourceType GetSourceType() return SourceType.Builtin; } + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Error; + } + /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// diff --git a/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 b/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 index dbbc97f08..8c32e9b4b 100644 --- a/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 +++ b/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 @@ -108,4 +108,16 @@ Describe "Test RuleExtension" { } } +} + +Describe "TestSeverity" { + It "filters rules based on the specified rule severity" { + $rules = Get-ScriptAnalyzerRule -Severity Error + $rules.Count | Should be 4 + } + + It "filters rules based on multiple severity inputs"{ + $rules = Get-ScriptAnalyzerRule -Severity Error,Information + $rules.Count | Should be 8 + } } \ No newline at end of file diff --git a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 index 53ddb9a02..9cc6ccdbd 100644 --- a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 +++ b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 @@ -3,6 +3,8 @@ $sa = Get-Command Invoke-ScriptAnalyzer $directory = Split-Path -Parent $MyInvocation.MyCommand.Path $singularNouns = "PSUseSingularNouns" $rules = $singularNouns, "PSUseApprovedVerbs" +$avoidRules = "PSAvoid*" +$useRules = "PSUse*" Describe "Test available parameters" { $params = $sa.Parameters @@ -103,6 +105,12 @@ Describe "Test ExcludeRule" { } } + Context "Support wild card" { + It "supports wild card exclusions of input rules"{ + $excludeWildCard = Invoke-ScriptAnalyzer $directory\..\Rules\BadCmdlet.ps1 -ExcludeRule $avoidRules | Where-Object {$_.RuleName -match $avoidRules} + } + } + } Describe "Test IncludeRule" { @@ -124,6 +132,18 @@ Describe "Test IncludeRule" { $wrongInclude.Count | Should Be 0 } } + + Context "IncludeRule supports wild card" { + It "includes 1 wildcard rule"{ + $includeWildcard = Invoke-ScriptAnalyzer $directory\..\Rules\BadCmdlet.ps1 -IncludeRule $avoidRules + $includeWildcard.Count | Should be 5 + } + + it "includes 2 wildcardrules" { + $includeWildcard = Invoke-ScriptAnalyzer $directory\..\Rules\BadCmdlet.ps1 -IncludeRule $avoidRules, $useRules + $includeWildcard.Count | Should be 7 + } + } } Describe "Test Exclude And Include" { diff --git a/Tests/Rules/AvoidGlobalOrUnitializedVars.ps1 b/Tests/Rules/AvoidGlobalOrUnitializedVars.ps1 index e9979a297..ef6988ad9 100644 --- a/Tests/Rules/AvoidGlobalOrUnitializedVars.ps1 +++ b/Tests/Rules/AvoidGlobalOrUnitializedVars.ps1 @@ -19,4 +19,7 @@ while ($false) { $a; # $d may not be initialized too -$d; \ No newline at end of file +$d; + +# error must be raised here +Invoke-Command -ScriptBlock {$a; } \ No newline at end of file diff --git a/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 b/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 index 537f57024..bad960927 100644 --- a/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 +++ b/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 @@ -31,8 +31,8 @@ Describe "AvoidGlobalVars" { Describe "AvoidUnitializedVars" { Context "When there are violations" { - It "has 4 avoid using unitialized variable violations" { - $nonInitializedViolations.Count | Should Be 4 + It "has 5 avoid using unitialized variable violations" { + $nonInitializedViolations.Count | Should Be 5 } It "has the correct description message" { diff --git a/Tests/Rules/AvoidGlobalOrUnitializedVarsNoViolations.ps1 b/Tests/Rules/AvoidGlobalOrUnitializedVarsNoViolations.ps1 index ca914bce5..b5206cd68 100644 --- a/Tests/Rules/AvoidGlobalOrUnitializedVarsNoViolations.ps1 +++ b/Tests/Rules/AvoidGlobalOrUnitializedVarsNoViolations.ps1 @@ -22,6 +22,8 @@ stop-process 12,23 -ErrorVariable ev -ErrorAction SilentlyContinue if($null -ne $ev) { Write-host $ev[0] + # no error should be raised here + Invoke-Command {$b} } get-process notepad | tee-object -variable proc diff --git a/Tests/Rules/AvoidUsingInternalURLsNoViolations.ps1 b/Tests/Rules/AvoidUsingInternalURLsNoViolations.ps1 index 73825de70..cdd8b7cc5 100644 --- a/Tests/Rules/AvoidUsingInternalURLsNoViolations.ps1 +++ b/Tests/Rules/AvoidUsingInternalURLsNoViolations.ps1 @@ -1,3 +1,4 @@ $correctPath = "www.bing.com" $externalSite = "//outside.co/test" -rmdir /s /q ".\Directory" \ No newline at end of file +rmdir /s /q ".\Directory" +$sd = "O:BAG:BAD:(A;;0x800;;;WD)(A;;0x120fff;;;SY)(A;;0x120fff;;;LS)(A;;0x120fff;;;NS)(A;;0x120fff;;;BA)(A;;0xee5;;;LU)(A;;LC;;;MU)(A;;0x800;;;AG)" \ No newline at end of file diff --git a/Tests/Rules/AvoidUsingWMIObjectCmdlet.ps1 b/Tests/Rules/AvoidUsingWMIObjectCmdlet.ps1 new file mode 100644 index 000000000..13f0412c9 --- /dev/null +++ b/Tests/Rules/AvoidUsingWMIObjectCmdlet.ps1 @@ -0,0 +1,13 @@ +#Script violates the rule because Get-CIMInstance is available on PS 3.0 and needs to use that + +#requires -version 3.0 + +function TestFunction +{ + Get-WmiObject -Class Win32_ComputerSystem + +} + +TestFunction + +Remove-WmiObject -Class Win32_OperatingSystem -Verbose \ No newline at end of file diff --git a/Tests/Rules/AvoidUsingWMIObjectCmdlet.tests.ps1 b/Tests/Rules/AvoidUsingWMIObjectCmdlet.tests.ps1 new file mode 100644 index 000000000..0a96ad16e --- /dev/null +++ b/Tests/Rules/AvoidUsingWMIObjectCmdlet.tests.ps1 @@ -0,0 +1,24 @@ +Import-Module PSScriptAnalyzer +$wmiObjectRuleName = "PSAvoidUsingWMIObjectCmdlet" +$violationMessage = "File 'AvoidUsingWMIObjectCmdlet.ps1' 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." +$directory = Split-Path -Parent $MyInvocation.MyCommand.Path +$violations = Invoke-ScriptAnalyzer $directory\AvoidUsingWMIObjectCmdlet.ps1 | Where-Object {$_.RuleName -eq $wmiObjectRuleName} +$noViolations = Invoke-ScriptAnalyzer $directory\AvoidUsingWMIObjectCmdletNoViolations.ps1 | Where-Object {$_.RuleName -eq $wmiObjectRuleName} + +Describe "AvoidUsingWMIObjectCmdlet" { + Context "Script contains references to WMIObject cmdlets - Violation" { + It "Have 2 WMIObject cmdlet Violations" { + $violations.Count | Should Be 2 + } + + It "has the correct description message for WMIObject rule violation" { + $violations[0].Message | Should Match $violationMessage + } + } + + Context "Script contains no calls to WMIObject cmdlet - No violation" { + It "results in no rule violations" { + $noViolations.Count | Should Be 0 + } + } +} \ No newline at end of file diff --git a/Tests/Rules/AvoidUsingWMIObjectCmdletNoViolations.ps1 b/Tests/Rules/AvoidUsingWMIObjectCmdletNoViolations.ps1 new file mode 100644 index 000000000..b5d2e6f14 --- /dev/null +++ b/Tests/Rules/AvoidUsingWMIObjectCmdletNoViolations.ps1 @@ -0,0 +1,14 @@ +# No Rule violations since this script requires PS 2.0 and Get-CIMInstance is not available for this version +# So using Get-WMIObject is OK + +#requires -Version 2.0 + +function TestFunction +{ + Remove-WmiObject -Class Win32_ComputerSystem + +} + +TestFunction + +Get-WmiObject -Class Win32_OperatingSystem -Verbose \ No newline at end of file diff --git a/Tests/Rules/UseShouldProcessForStateChangingFunctions.ps1 b/Tests/Rules/UseShouldProcessForStateChangingFunctions.ps1 index 925a1b809..9898f7f87 100644 --- a/Tests/Rules/UseShouldProcessForStateChangingFunctions.ps1 +++ b/Tests/Rules/UseShouldProcessForStateChangingFunctions.ps1 @@ -1,11 +1,11 @@ -function Get-Service -{ - param ([string]$c) -} - -function Get-MyObject{ +function Set-MyObject{ [CmdletBinding(SupportsShouldProcess = $false)] param([string]$c, [int]$d) } +function Set-MyObject{ + [CmdletBinding()] + param([string]$c, [int]$d) + +} \ No newline at end of file diff --git a/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1 b/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1 index e5998e00e..0cbdecc5e 100644 --- a/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1 +++ b/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1 @@ -1,15 +1,14 @@ Import-Module PSScriptAnalyzer -$violationMessage = "Function ’Get-Service’ has verb that could change system state. Therefore, the function has to support 'ShouldProcess'" +$violationMessage = "Function ’Set-MyObject’ has verb that could change system state. Therefore, the function has to support 'ShouldProcess'" $violationName = "PSUseShouldProcessForStateChangingFunctions" -$violationName = "PS.UseShouldProcessForStateChangingFunctions" $directory = Split-Path -Parent $MyInvocation.MyCommand.Path $violations = Invoke-ScriptAnalyzer $directory\UseShouldProcessForStateChangingFunctions.ps1 | Where-Object {$_.RuleName -eq $violationName} $noViolations = Invoke-ScriptAnalyzer $directory\UseShouldProcessForStateChangingFunctionsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName} -Describe "" { +Describe "It checks UseShouldProcess is enabled when there are state changing verbs in the function names" { Context "When there are violations" { It "has 2 violations where ShouldProcess is not supported" { - $violations.Count | Should Be 3 + $violations.Count | Should Be 2 } It "has the correct description message" { diff --git a/Tests/Rules/UseShouldProcessForStateChangingFunctionsNoViolations.ps1 b/Tests/Rules/UseShouldProcessForStateChangingFunctionsNoViolations.ps1 index cb4b2cfc9..a9f3d8aee 100644 --- a/Tests/Rules/UseShouldProcessForStateChangingFunctionsNoViolations.ps1 +++ b/Tests/Rules/UseShouldProcessForStateChangingFunctionsNoViolations.ps1 @@ -1,6 +1,6 @@ -function Get-Service +function Set-Service { - [CmdletBinding(SupportShouldSuppress= $false)] + [CmdletBinding(SupportsShouldProcess = $true)] param ([string]$c) }