From b7ef03d9294403ff521191d3211fc5c9aae69106 Mon Sep 17 00:00:00 2001 From: Liam Peters Date: Mon, 12 Jan 2026 13:19:06 +0000 Subject: [PATCH 1/3] Remove conditional compilation gates using PSV3 and PSV4 --- .../Commands/InvokeScriptAnalyzerCommand.cs | 4 - Engine/FindAstPositionVisitor.cs | 6 - Engine/Generic/IDSCResourceRule.cs | 4 - Engine/Generic/ModuleDependencyHandler.cs | 4 +- Engine/Generic/RuleSuppression.cs | 2 - Engine/Helper.cs | 140 +----------------- Engine/ScriptAnalyzer.cs | 53 +------ Engine/VariableAnalysis.cs | 36 ----- Engine/VariableAnalysisBase.cs | 70 +-------- Rules/AlignAssignmentStatement.cs | 2 - Rules/AvoidGlobalAliases.cs | 5 +- .../CompatibilityRules/UseCompatibleSyntax.cs | 6 - Rules/DscExamplesPresent.cs | 4 - Rules/DscTestsPresent.cs | 4 - Rules/PossibleIncorrectComparisonWithNull.cs | 8 - Rules/ReturnCorrectTypesForDSCFunctions.cs | 17 --- Rules/Rules.csproj | 8 - Rules/UseIdenticalMandatoryParametersDSC.cs | 6 +- Rules/UseOutputTypeCorrectly.cs | 16 -- Rules/UseStandardDSCFunctionsInResource.cs | 8 - Rules/UseUsingScopeModifierInNewRunspaces.cs | 4 - 21 files changed, 7 insertions(+), 400 deletions(-) diff --git a/Engine/Commands/InvokeScriptAnalyzerCommand.cs b/Engine/Commands/InvokeScriptAnalyzerCommand.cs index a444327e0..bf1e740c3 100644 --- a/Engine/Commands/InvokeScriptAnalyzerCommand.cs +++ b/Engine/Commands/InvokeScriptAnalyzerCommand.cs @@ -227,7 +227,6 @@ public object Settings private bool stopProcessing; -#if !PSV3 /// /// Resolve DSC resource dependency /// @@ -238,7 +237,6 @@ public SwitchParameter SaveDscDependency set { saveDscDependency = value; } } private bool saveDscDependency; -#endif // !PSV3 #if DEBUG /// @@ -387,7 +385,6 @@ protected override void ProcessRecord() ProcessPath(); } -#if !PSV3 // TODO Support dependency resolution for analyzing script definitions if (saveDscDependency) { @@ -407,7 +404,6 @@ protected override void ProcessRecord() } return; } -#endif ProcessInput(); } diff --git a/Engine/FindAstPositionVisitor.cs b/Engine/FindAstPositionVisitor.cs index 459581cbc..c281cfef2 100644 --- a/Engine/FindAstPositionVisitor.cs +++ b/Engine/FindAstPositionVisitor.cs @@ -8,11 +8,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer /// /// Provides an efficient way to find the position in the AST corresponding to a given script position. /// -#if !(PSV3 || PSV4) internal class FindAstPositionVisitor : AstVisitor2 -#else - internal class FindAstPositionVisitor : AstVisitor -#endif { private IScriptPosition searchPosition; @@ -300,7 +296,6 @@ public override AstVisitAction VisitWhileStatement(WhileStatementAst whileStatem return Visit(whileStatementAst); } -#if !(PSV3 || PSV4) public override AstVisitAction VisitBaseCtorInvokeMemberExpression(BaseCtorInvokeMemberExpressionAst baseCtorInvokeMemberExpressionAst) { return Visit(baseCtorInvokeMemberExpressionAst); @@ -335,7 +330,6 @@ public override AstVisitAction VisitUsingStatement(UsingStatementAst usingStatem { return AstVisitAction.Continue; } -#endif #if !(NET462 || PSV7) // net462 includes V3,4,5 public override AstVisitAction VisitPipelineChain(PipelineChainAst pipelineChainAst) diff --git a/Engine/Generic/IDSCResourceRule.cs b/Engine/Generic/IDSCResourceRule.cs index 3ef20cde7..5f4c2da64 100644 --- a/Engine/Generic/IDSCResourceRule.cs +++ b/Engine/Generic/IDSCResourceRule.cs @@ -19,8 +19,6 @@ public interface IDSCResourceRule : IRule /// The results of the analysis IEnumerable AnalyzeDSCResource(Ast ast, string fileName); - #if !PSV3 - /// /// Analyze dsc classes (if any) in the file /// @@ -29,7 +27,5 @@ public interface IDSCResourceRule : IRule /// IEnumerable AnalyzeDSCClass(Ast ast, string fileName); - #endif - } } \ No newline at end of file diff --git a/Engine/Generic/ModuleDependencyHandler.cs b/Engine/Generic/ModuleDependencyHandler.cs index 31a43d6ca..91e557d64 100644 --- a/Engine/Generic/ModuleDependencyHandler.cs +++ b/Engine/Generic/ModuleDependencyHandler.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if !PSV3 using System; using System.Collections.Generic; using System.IO; @@ -519,5 +518,4 @@ public void Dispose() #endregion Public Methods } -} -#endif // !PSV3 \ No newline at end of file +} \ No newline at end of file diff --git a/Engine/Generic/RuleSuppression.cs b/Engine/Generic/RuleSuppression.cs index 7daab3e86..279eec58f 100644 --- a/Engine/Generic/RuleSuppression.cs +++ b/Engine/Generic/RuleSuppression.cs @@ -333,12 +333,10 @@ public static List GetSuppressions(IEnumerable at { targetAsts = scopeAst.FindAll(ast => ast is FunctionDefinitionAst && reg.IsMatch((ast as FunctionDefinitionAst).Name), true); } -#if !(PSV3 || PSV4) else if (scope.Equals("class", StringComparison.OrdinalIgnoreCase)) { targetAsts = scopeAst.FindAll(ast => ast is TypeDefinitionAst && reg.IsMatch((ast as TypeDefinitionAst).Name), true); } -#endif if (targetAsts != null) { diff --git a/Engine/Helper.cs b/Engine/Helper.cs index 098d8a276..a162bfbcf 100644 --- a/Engine/Helper.cs +++ b/Engine/Helper.cs @@ -512,8 +512,6 @@ public bool IsDscResourceClassBased(ScriptBlockAst ast) return false; } - #if !(PSV3||PSV4) - List dscResourceFunctionNames = new List(new string[] { "Test", "Get", "Set" }); IEnumerable dscClasses = ast.FindAll(item => @@ -528,8 +526,6 @@ item is TypeDefinitionAst return true; } - #endif - return false; } @@ -953,15 +949,7 @@ internal VariableAnalysis InitializeVariableAnalysisHelper(Ast ast, VariableAnal /// /// -#if (PSV3||PSV4) - - public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret) - -#else - public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret, IEnumerable classes) - -#endif { if (ret == null || funcAst == null) { @@ -992,15 +980,7 @@ public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret, } else if (cmAst.Expression is MemberExpressionAst) { -#if PSV3 - - result = GetTypeFromMemberExpressionAst(cmAst.Expression as MemberExpressionAst, funcAst); - -#else - result = GetTypeFromMemberExpressionAst(cmAst.Expression as MemberExpressionAst, funcAst, classes); - -#endif } } } @@ -1024,15 +1004,7 @@ public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret, /// /// -#if (PSV3||PSV4) - - public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast scopeAst) - -#else - public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast scopeAst, IEnumerable classes) - -#endif { if (memberAst == null) { @@ -1041,38 +1013,22 @@ public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast VariableAnalysisDetails details = null; -#if !(PSV3||PSV4) - TypeDefinitionAst psClass = null; -#endif - if (memberAst.Expression is VariableExpressionAst && VariableAnalysisDictionary.ContainsKey(scopeAst)) { VariableAnalysis VarTypeAnalysis = VariableAnalysisDictionary[scopeAst]; // Get the analysis detail for the variable details = VarTypeAnalysis.GetVariableAnalysis(memberAst.Expression as VariableExpressionAst); -#if !PSV3 - if (details != null && classes != null) { // Get the class that corresponds to the name of the type (if possible, the type is not available in the case of a static Singleton) psClass = classes.FirstOrDefault(item => String.Equals(item.Name, details.Type?.FullName, StringComparison.OrdinalIgnoreCase)); } - -#endif } -#if PSV3 - - return GetTypeFromMemberExpressionAstHelper(memberAst, details); - -#else - - return GetTypeFromMemberExpressionAstHelper(memberAst, psClass, details); - -#endif + return GetTypeFromMemberExpressionAstHelper(memberAst, psClass, details); } /// @@ -1084,28 +1040,17 @@ public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast /// /// -#if (PSV3||PSV4) - - internal string GetTypeFromMemberExpressionAstHelper(MemberExpressionAst memberAst, VariableAnalysisDetails analysisDetails) - -#else - internal string GetTypeFromMemberExpressionAstHelper(MemberExpressionAst memberAst, TypeDefinitionAst psClass, VariableAnalysisDetails analysisDetails) - -#endif { //Try to get the type without using psClass first Type result = AssignmentTarget.GetTypeFromMemberExpressionAst(memberAst); -#if !(PSV3||PSV4) - //If we can't get the type, then it may be that the type of the object being invoked on is a powershell class if (result == null && psClass != null && analysisDetails != null) { result = AssignmentTarget.GetTypeFromMemberExpressionAst(memberAst, analysisDetails, psClass); } -#endif if (result != null) { @@ -1205,7 +1150,6 @@ public Dictionary> GetRuleSuppression(Ast ast) ruleSuppressionList.AddRange(GetSuppressionsFunction(funcAst)); } -#if !(PSV3||PSV4) // Get rule suppression from classes IEnumerable typeAsts = ast.FindAll(item => item is TypeDefinitionAst, true).Cast(); @@ -1221,7 +1165,6 @@ public Dictionary> GetRuleSuppression(Ast ast) { ruleSuppressionList.AddRange(GetSuppressionsConfiguration(configDefAst)); } -#endif // !PSV3 ruleSuppressionList.Sort((item, item2) => item.StartOffset.CompareTo(item2.StartOffset)); @@ -1257,7 +1200,6 @@ internal List GetSuppressionsFunction(FunctionDefinitionAst fun return result; } -#if !(PSV3||PSV4) /// /// Returns a list of rule suppression from the class /// @@ -1313,8 +1255,6 @@ internal List GetSuppressionsConfiguration(ConfigurationDefinit return result; } -#endif // !PSV3 - /// /// Suppress the rules from the diagnostic records list. /// Returns a list of suppressed records as well as the ones that are not suppressed @@ -2116,15 +2056,8 @@ public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) // 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 PSV3 - - if (!(scriptBlockAst.Parent is FunctionDefinitionAst)) - -#else if (!(scriptBlockAst.Parent is FunctionDefinitionAst) && !(scriptBlockAst.Parent is FunctionMemberAst)) - -#endif { OuterAnalysis = Helper.Instance.InitializeVariableAnalysisHelper(scriptBlockAst, OuterAnalysis); } @@ -2152,15 +2085,7 @@ public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) VariableAnalysis innerAnalysis = OuterAnalysis; OuterAnalysis = previousOuter; -#if PSV3 - - if (!(scriptBlockAst.Parent is FunctionDefinitionAst)) - -#else - if (!(scriptBlockAst.Parent is FunctionDefinitionAst) && !(scriptBlockAst.Parent is FunctionMemberAst)) - -#endif { // Update the variable analysis of the outer script block VariableAnalysis.UpdateOuterAnalysis(OuterAnalysis, innerAnalysis); @@ -2181,12 +2106,6 @@ private object VisitStatementHelper(StatementAst statementAst) return null; } -#if (PSV3||PSV4) - - statementAst.Visit(this); - -#else - TypeDefinitionAst typeAst = statementAst as TypeDefinitionAst; if (typeAst == null) @@ -2212,14 +2131,9 @@ private object VisitStatementHelper(StatementAst statementAst) OuterAnalysis = previousOuter; } } - -#endif - return null; } -#if !PSV3 - /// /// Do nothing /// @@ -2230,8 +2144,6 @@ public object VisitUsingStatement(UsingStatementAst usingStatement) return null; } -#endif - /// /// Do nothing /// @@ -2897,12 +2809,8 @@ public class FindPipelineOutput : ICustomAstVisitor { List> outputTypes; -#if !(PSV3||PSV4) - IEnumerable classes; -#endif - FunctionDefinitionAst myFunction; /// /// These binary operators will always return boolean value @@ -2939,24 +2847,12 @@ static FindPipelineOutput() /// /// -#if (PSV3||PSV4) - - public FindPipelineOutput(FunctionDefinitionAst ast) - -#else - public FindPipelineOutput(FunctionDefinitionAst ast, IEnumerable classes) - -#endif { outputTypes = new List>(); -#if !PSV3 - this.classes = classes; -#endif - myFunction = ast; if (myFunction != null) @@ -2970,21 +2866,11 @@ public FindPipelineOutput(FunctionDefinitionAst ast, IEnumerable /// -#if (PSV3||PSV4) - - public static List> OutputTypes(FunctionDefinitionAst funcAst) - { - return (new FindPipelineOutput(funcAst)).outputTypes; - } - -#else public static List> OutputTypes(FunctionDefinitionAst funcAst, IEnumerable classes) { return (new FindPipelineOutput(funcAst, classes)).outputTypes; } -#endif - /// /// Ignore assignment statement /// @@ -3436,15 +3322,7 @@ public object VisitCommandExpression(CommandExpressionAst commandAst) /// public object VisitReturnStatement(ReturnStatementAst returnStatementAst) { -#if PSV3 - - return Helper.Instance.GetTypeFromReturnStatementAst(myFunction, returnStatementAst); - -#else - return Helper.Instance.GetTypeFromReturnStatementAst(myFunction, returnStatementAst, classes); - -#endif } /// @@ -3454,15 +3332,7 @@ public object VisitReturnStatement(ReturnStatementAst returnStatementAst) /// public object VisitMemberExpression(MemberExpressionAst memAst) { -#if PSV3 - - return Helper.Instance.GetTypeFromMemberExpressionAst(memAst, myFunction); - -#else - return Helper.Instance.GetTypeFromMemberExpressionAst(memAst, myFunction, classes); - -#endif } /// @@ -3472,15 +3342,7 @@ public object VisitMemberExpression(MemberExpressionAst memAst) /// public object VisitInvokeMemberExpression(InvokeMemberExpressionAst invokeAst) { -#if PSV3 - - return Helper.Instance.GetTypeFromMemberExpressionAst(invokeAst, myFunction); - -#else - return Helper.Instance.GetTypeFromMemberExpressionAst(invokeAst, myFunction, classes); - -#endif } /// diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs index f250336b5..c564dc8fa 100644 --- a/Engine/ScriptAnalyzer.cs +++ b/Engine/ScriptAnalyzer.cs @@ -50,9 +50,7 @@ public sealed class ScriptAnalyzer List includeRegexList; List excludeRegexList; private SuppressionPreference _suppressionPreference; -#if !PSV3 ModuleDependencyHandler moduleHandler; -#endif #endregion #region Singleton @@ -98,7 +96,6 @@ public static ScriptAnalyzer Instance internal List ExternalRules { get; set; } -#if !PSV3 public ModuleDependencyHandler ModuleHandler { get { @@ -110,7 +107,6 @@ internal set moduleHandler = value; } } -#endif #endregion @@ -622,36 +618,6 @@ private bool ParseProfileString(string profile, PathIntrinsics path, IOutputWrit else { HashtableAst hashTableAst = hashTableAsts.First() as HashtableAst; -#if PSV3 - settings = GetDictionaryFromHashTableAst( - hashTableAst, - writer, - profile, - out hasError); - foreach (var key in settings.Keys) - { - var rhsList = settings[key] as List; - if (rhsList == null) - { - continue; - } - if (!AddProfileItem(key, rhsList, severityList, includeRuleList, excludeRuleList)) - { - writer.WriteError( - new ErrorRecord( - new InvalidDataException( - string.Format( - CultureInfo.CurrentCulture, - Strings.WrongKey, - key, - profile)), - Strings.WrongConfigurationKey, - ErrorCategory.InvalidData, - profile)); - hasError = true; - } - } -#else try { @@ -668,7 +634,6 @@ private bool ParseProfileString(string profile, PathIntrinsics path, IOutputWrit profile)); hasError = true; } -#endif // PSV3 } } @@ -691,10 +656,7 @@ private void Initialize( { throw new ArgumentNullException("outputWriter"); } -#if !PSV3 this.moduleHandler = null; -#endif - this.outputWriter = outputWriter; #region Verifies rule extensions @@ -1843,7 +1805,6 @@ private void BuildScriptPathList( } } -#if !PSV3 private bool TrySaveModules(ParseError[] errors, ScriptBlockAst scriptAst) { bool modulesSaved = false; @@ -1877,7 +1838,6 @@ private bool TrySaveModules(ParseError[] errors, ScriptBlockAst scriptAst) } return modulesSaved; } -#endif // !PSV3 private IEnumerable AnalyzeFile(string filePath) { @@ -1915,13 +1875,13 @@ private IEnumerable AnalyzeFile(string filePath) this.outputWriter.WriteWarning(e.ToString()); return null; } -#if !PSV3 + //try parsing again if (TrySaveModules(errors, scriptAst)) { scriptAst = Parser.ParseFile(filePath, out scriptTokens, out errors); } -#endif //!PSV3 + IEnumerable relevantParseErrors = RemoveTypeNotFoundParseErrors(errors, out diagnosticRecords); // First, add all parse errors if they've been requested @@ -2254,17 +2214,8 @@ public IEnumerable AnalyzeSyntaxTree( // We want the Engine to continue functioning even if one or more Rules throws an exception try { -#if PSV3 - var errRecs = new List(); - var records = Helper.Instance.SuppressRule( - dscResourceRule.GetName(), - ruleSuppressions, - null, - out errRecs); -#else var ruleRecords = dscResourceRule.AnalyzeDSCClass(scriptAst, filePath).ToList(); var records = SuppressRule(dscResourceRule.GetName(), ruleSuppressions, ruleRecords); -#endif foreach (var record in records.Item2) { diagnostics.Add(record); diff --git a/Engine/VariableAnalysis.cs b/Engine/VariableAnalysis.cs index 2870d442f..2bb8068d4 100644 --- a/Engine/VariableAnalysis.cs +++ b/Engine/VariableAnalysis.cs @@ -134,15 +134,7 @@ private void ProcessParameters(IEnumerable parameters) public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) { - #if PSV3 - - if (!(ast is ScriptBlockAst || ast is FunctionDefinitionAst)) - - #else - if (!(ast is ScriptBlockAst || ast is FunctionMemberAst || ast is FunctionDefinitionAst)) - - #endif { return; } @@ -151,15 +143,7 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) Init(); - #if PSV3 - - if (ast is FunctionDefinitionAst) - - #else - if (ast is FunctionMemberAst || ast is FunctionDefinitionAst) - - #endif { IEnumerable parameters = FindParameters(ast, ast.GetType()); if (parameters != null) @@ -176,20 +160,11 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) } } - #if PSV3 - - if (ast is FunctionDefinitionAst) - - #else - if (ast is FunctionMemberAst) { (ast as FunctionMemberAst).Body.Visit(this.Decorator); } else if (ast is FunctionDefinitionAst) - - #endif - { (ast as FunctionDefinitionAst).Body.Visit(this.Decorator); } @@ -205,14 +180,10 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) parent = parent.Parent; } - #if !(PSV3||PSV4) - List classes = parent.FindAll(item => item is TypeDefinitionAst && (item as TypeDefinitionAst).IsClass, true) .Cast().ToList(); - #endif - if (outerAnalysis != null) { // Initialize the variables from outside @@ -250,15 +221,8 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) } } - #if PSV3 - - var dictionaries = Block.SparseSimpleConstants(_variables, Entry); - - #else - var dictionaries = Block.SparseSimpleConstants(_variables, Entry, classes); - #endif VariablesDictionary = dictionaries.Item1; InternalVariablesDictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/Engine/VariableAnalysisBase.cs b/Engine/VariableAnalysisBase.cs index 77c421f3c..218bdc8ea 100644 --- a/Engine/VariableAnalysisBase.cs +++ b/Engine/VariableAnalysisBase.cs @@ -97,16 +97,7 @@ public class FindAllVariablesVisitor : AstVisitor /// public static Dictionary Visit(Ast ast) { - #if PSV3 - - if (!(ast is ScriptBlockAst || ast is FunctionDefinitionAst)) - - #else - if (!(ast is ScriptBlockAst || ast is FunctionMemberAst || ast is FunctionDefinitionAst)) - - #endif - { return null; } @@ -122,34 +113,20 @@ public static Dictionary Visit(Ast ast) { (ast as ScriptBlockAst).Visit(visitor); } - - #if !PSV3 - else if (ast is FunctionMemberAst) { (ast as FunctionMemberAst).Body.Visit(visitor); } - - #endif - else if (ast is FunctionDefinitionAst) { (ast as FunctionDefinitionAst).Body.Visit(visitor); } - #if PSV3 - - if (ast is FunctionDefinitionAst && (ast as FunctionDefinitionAst).Parameters != null) - - #else - if (ast is FunctionMemberAst && (ast as FunctionMemberAst).Parameters != null) { visitor.VisitParameters((ast as FunctionMemberAst).Parameters); } else if (ast is FunctionDefinitionAst && (ast as FunctionDefinitionAst).Parameters != null) - - #endif { visitor.VisitParameters((ast as FunctionDefinitionAst).Parameters); } @@ -165,8 +142,6 @@ internal void InitializeVariables(Ast ast) _variables.Add("true", new VariableAnalysisDetails { Name = "true", RealName = "true", Type = typeof(bool) }); _variables.Add("false", new VariableAnalysisDetails { Name = "false", RealName = "true", Type = typeof(bool) }); - #if !(PSV3||PSV4) - if (ast is FunctionMemberAst) { TypeDefinitionAst psClass = AssignmentTarget.FindClassAncestor(ast); @@ -175,9 +150,6 @@ internal void InitializeVariables(Ast ast) _variables.Add("this", new VariableAnalysisDetails { Name = "this", RealName = "this", Constant = SpecialVars.ThisVariable }); } } - - #endif - } internal void VisitParameters(ReadOnlyCollection parameters) @@ -808,16 +780,8 @@ internal static void InitializeSSA(Dictionary V /// /// /// - #if (PSV3||PSV4) - internal static Tuple, Dictionary> SparseSimpleConstants( - Dictionary Variables, Block Entry) - - #else - internal static Tuple, Dictionary> SparseSimpleConstants( - Dictionary Variables, Block Entry, List Classes) - - #endif + Dictionary Variables, Block Entry, List Classes) { List blocks = GenerateReverseDepthFirstOrder(Entry); @@ -989,17 +953,9 @@ internal static Tuple, Dictionary String.Equals(item.Name, analysis.Type?.FullName, StringComparison.OrdinalIgnoreCase)); Type possibleType = AssignmentTarget.GetTypeFromMemberExpressionAst(memAst, analysis, psClass); - #endif - if (possibleType != null && possibleType != assigned.Type) { assigned.Type = possibleType; @@ -1370,24 +1326,13 @@ public AssignmentTarget(string variableName, Type type) /// /// /// - - #if (PSV3||PSV4) - - internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memAst, VariableAnalysisDetails analysis) - - #else - internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memAst, VariableAnalysisDetails analysis, TypeDefinitionAst psClass) - - #endif { if (memAst != null && memAst.Expression is VariableExpressionAst && memAst.Member is StringConstantExpressionAst && !String.Equals((memAst.Expression as VariableExpressionAst).VariablePath.UserPath, "this", StringComparison.OrdinalIgnoreCase)) { string fieldName = (memAst.Member as StringConstantExpressionAst).Value; - #if !PSV3 - if (psClass == null && analysis.Constant == SpecialVars.ThisVariable) { psClass = AssignmentTarget.FindClassAncestor(memAst); @@ -1404,8 +1349,6 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memAst, } } - #endif - // If the type is not a ps class or there are some types of the same name. if (analysis != null && analysis.Type != null && analysis.Type != typeof(object) && analysis.Type != typeof(Unreached) && analysis.Type != typeof(Undetermined)) @@ -1460,7 +1403,6 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs // isStatic is true result = GetTypeFromInvokeMemberAst(type, imeAst, methodName, true); } - #if !(PSV3||PSV4) else { // Check for classes @@ -1478,7 +1420,6 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs } } } - #endif } #endregion @@ -1498,7 +1439,6 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs { result = GetPropertyOrFieldTypeFromMemberExpressionAst(expressionType, fieldName); } - #if !(PSV3||PSV4) else { // check for class type @@ -1514,7 +1454,6 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs } } } - #endif } #endregion @@ -1531,15 +1470,11 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs if (memberAst.Expression is VariableExpressionAst && String.Equals((memberAst.Expression as VariableExpressionAst).VariablePath.UserPath, "this", StringComparison.OrdinalIgnoreCase)) { - #if !(PSV3||PSV4) - // Check that we are in a class TypeDefinitionAst psClass = FindClassAncestor(memberAst); // Is static is false for this case result = GetTypeFromClass(psClass, memberAst); - - #endif } return result; @@ -1598,7 +1533,6 @@ internal static Type GetPropertyOrFieldTypeFromMemberExpressionAst(Type type, st return result; } -#if !(PSV3||PSV4) /// /// Checks whether a class with the name name exists in the script that contains ast /// @@ -1686,8 +1620,6 @@ internal static Type GetTypeFromClass(TypeDefinitionAst psClass, MemberExpressio return result; } -#endif // !PSV3 - private void SetVariableName() { ExpressionAst lhs = (_targetAst is ConvertExpressionAst) ? (_targetAst as ConvertExpressionAst).Child : _targetAst; diff --git a/Rules/AlignAssignmentStatement.cs b/Rules/AlignAssignmentStatement.cs index 1d79870f2..14cce7d37 100644 --- a/Rules/AlignAssignmentStatement.cs +++ b/Rules/AlignAssignmentStatement.cs @@ -147,7 +147,6 @@ private IEnumerable FindHashtableViolations(TokenOperations to } } -#if !PSV3 var configAsts = tokenOps.Ast.FindAll(ast => ast is ConfigurationDefinitionAst, true); if (configAsts != null) { @@ -163,7 +162,6 @@ private IEnumerable FindHashtableViolations(TokenOperations to groups.AddRange(GetCommandElementExtentGroups(configAst)); } } -#endif // it is probably much easier have a hashtable writer that formats the hashtable and writes it // but it makes handling comments hard. So we need to use this approach. diff --git a/Rules/AvoidGlobalAliases.cs b/Rules/AvoidGlobalAliases.cs index afe7978e6..8697ad1ca 100644 --- a/Rules/AvoidGlobalAliases.cs +++ b/Rules/AvoidGlobalAliases.cs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#if !PSV3 using System; using System.Collections.Generic; #if !CORECLR @@ -136,6 +135,4 @@ public SourceType GetSourceType() return SourceType.Builtin; } } -} - -#endif // !PSV3 \ No newline at end of file +} \ No newline at end of file diff --git a/Rules/CompatibilityRules/UseCompatibleSyntax.cs b/Rules/CompatibilityRules/UseCompatibleSyntax.cs index 3af6cdd1c..c7d10c19d 100644 --- a/Rules/CompatibilityRules/UseCompatibleSyntax.cs +++ b/Rules/CompatibilityRules/UseCompatibleSyntax.cs @@ -149,11 +149,7 @@ private static HashSet GetTargetedVersions(string[] versionSettings) return targetVersions; } -#if !(PSV3 || PSV4) private class SyntaxCompatibilityVisitor : AstVisitor2 -#else - private class SyntaxCompatibilityVisitor : AstVisitor -#endif { private readonly UseCompatibleSyntax _rule; @@ -260,7 +256,6 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun return AstVisitAction.Continue; } -#if !(PSV3 || PSV4) public override AstVisitAction VisitUsingStatement(UsingStatementAst usingStatementAst) { // Look for 'using ...;' at the top of scripts @@ -306,7 +301,6 @@ public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinit return AstVisitAction.Continue; } -#endif #if PSV7 public override AstVisitAction VisitMemberExpression(MemberExpressionAst memberExpressionAst) diff --git a/Rules/DscExamplesPresent.cs b/Rules/DscExamplesPresent.cs index 6d0a01a3b..17cca2a1c 100644 --- a/Rules/DscExamplesPresent.cs +++ b/Rules/DscExamplesPresent.cs @@ -65,8 +65,6 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName } } - #if !(PSV3||PSV4) - /// /// AnalyzeDSCClass: Analyzes given DSC class /// @@ -116,8 +114,6 @@ item is TypeDefinitionAst } } - #endif - /// /// GetName: Retrieves the name of this rule. /// diff --git a/Rules/DscTestsPresent.cs b/Rules/DscTestsPresent.cs index 5c09ede8a..3a19902d9 100644 --- a/Rules/DscTestsPresent.cs +++ b/Rules/DscTestsPresent.cs @@ -65,8 +65,6 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName } } - #if !(PSV3||PSV4) - /// /// AnalyzeDSCClass: Analyzes given DSC class /// @@ -116,8 +114,6 @@ item is TypeDefinitionAst } } - #endif - /// /// GetName: Retrieves the name of this rule. /// diff --git a/Rules/PossibleIncorrectComparisonWithNull.cs b/Rules/PossibleIncorrectComparisonWithNull.cs index 74db4f523..3302583ae 100644 --- a/Rules/PossibleIncorrectComparisonWithNull.cs +++ b/Rules/PossibleIncorrectComparisonWithNull.cs @@ -44,16 +44,8 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) { } } - #if PSV3 - - IEnumerable funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true); - - #else - IEnumerable funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true).Union(ast.FindAll(item => item is FunctionMemberAst, true)); - #endif - foreach (Ast funcAst in funcAsts) { IEnumerable binAsts = funcAst.FindAll(item => item is BinaryExpressionAst, true); diff --git a/Rules/ReturnCorrectTypesForDSCFunctions.cs b/Rules/ReturnCorrectTypesForDSCFunctions.cs index 08eb59df0..0c750571c 100644 --- a/Rules/ReturnCorrectTypesForDSCFunctions.cs +++ b/Rules/ReturnCorrectTypesForDSCFunctions.cs @@ -35,28 +35,16 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName IEnumerable functionDefinitionAsts = Helper.Instance.DscResourceFunctions(ast); - #if !(PSV3||PSV4) - IEnumerable classes = ast.FindAll(item => item is TypeDefinitionAst && ((item as TypeDefinitionAst).IsClass), true).Cast(); - #endif foreach (FunctionDefinitionAst func in functionDefinitionAsts) { - #if PSV3 || PSV4 - - List> outputTypes = FindPipelineOutput.OutputTypes(func); - - #else - List> outputTypes = FindPipelineOutput.OutputTypes(func, classes); - #endif - - if (String.Equals(func.Name, "Set-TargetResource", StringComparison.OrdinalIgnoreCase)) { foreach (Tuple outputType in outputTypes) @@ -93,8 +81,6 @@ item is TypeDefinitionAst } } - #if !(PSV3||PSV4) - /// /// AnalyzeDSCClass: Analyzes given DSC Resource /// @@ -184,9 +170,6 @@ item is TypeDefinitionAst } } - #endif - - /// /// GetName: Retrieves the name of this rule. /// diff --git a/Rules/Rules.csproj b/Rules/Rules.csproj index 6e485c4e9..7641bb033 100644 --- a/Rules/Rules.csproj +++ b/Rules/Rules.csproj @@ -53,14 +53,6 @@ PrepareResources;$(CompileDependsOn) - - $(DefineConstants);PSV3 - - - - $(DefineConstants);PSV3;PSV4 - - $(DefineConstants);PSV7;CORECLR diff --git a/Rules/UseIdenticalMandatoryParametersDSC.cs b/Rules/UseIdenticalMandatoryParametersDSC.cs index 56acb5b48..9c453e3a1 100644 --- a/Rules/UseIdenticalMandatoryParametersDSC.cs +++ b/Rules/UseIdenticalMandatoryParametersDSC.cs @@ -2,8 +2,6 @@ // Licensed under the MIT License. // this rule can only compile on v4+ -#if (PSV4 || !PSV3) - using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -334,6 +332,4 @@ private FileInfo GetModuleManifest(string fileName) .FirstOrDefault(); } } -} - -#endif +} \ No newline at end of file diff --git a/Rules/UseOutputTypeCorrectly.cs b/Rules/UseOutputTypeCorrectly.cs index 099cd9f25..ac7ff4a01 100644 --- a/Rules/UseOutputTypeCorrectly.cs +++ b/Rules/UseOutputTypeCorrectly.cs @@ -22,12 +22,8 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules #endif public class UseOutputTypeCorrectly : SkipTypeDefinition, IScriptRule { - #if !(PSV3||PSV4) - private IEnumerable _classes; - #endif - /// /// AnalyzeScript: Checks that objects returned in a cmdlet have their types declared in OutputType Attribute /// @@ -41,12 +37,8 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) DiagnosticRecords.Clear(); this.fileName = fileName; - #if !(PSV3||PSV4) - _classes = ast.FindAll(item => item is TypeDefinitionAst && ((item as TypeDefinitionAst).IsClass), true).Cast(); - #endif - ast.Visit(this); return DiagnosticRecords; @@ -103,16 +95,8 @@ public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst fun } } - #if PSV3 - - List> returnTypes = FindPipelineOutput.OutputTypes(funcAst); - - #else - List> returnTypes = FindPipelineOutput.OutputTypes(funcAst, _classes); - #endif - HashSet specialTypes = new HashSet(StringComparer.OrdinalIgnoreCase); specialTypes.Add(typeof(Unreached).FullName); specialTypes.Add(typeof(Undetermined).FullName); diff --git a/Rules/UseStandardDSCFunctionsInResource.cs b/Rules/UseStandardDSCFunctionsInResource.cs index 7022da2d4..386198ba5 100644 --- a/Rules/UseStandardDSCFunctionsInResource.cs +++ b/Rules/UseStandardDSCFunctionsInResource.cs @@ -64,12 +64,6 @@ public IEnumerable AnalyzeDSCClass(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); - #if (PSV3||PSV4) - - return null; - - #else - List resourceFunctionNames = new List(new string[] {"Test", "Get", "Set"}); IEnumerable dscClasses = ast.FindAll(item => @@ -90,8 +84,6 @@ item is TypeDefinitionAst } } } - - #endif } /// diff --git a/Rules/UseUsingScopeModifierInNewRunspaces.cs b/Rules/UseUsingScopeModifierInNewRunspaces.cs index a435c1d31..46e1eea8a 100644 --- a/Rules/UseUsingScopeModifierInNewRunspaces.cs +++ b/Rules/UseUsingScopeModifierInNewRunspaces.cs @@ -91,11 +91,7 @@ public string GetSourceName() return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); } -#if !(PSV3 || PSV4) private class SyntaxCompatibilityVisitor : AstVisitor2 -#else - private class SyntaxCompatibilityVisitor : AstVisitor -#endif { private const DiagnosticSeverity Severity = DiagnosticSeverity.Warning; From 3d8013afb5e356a484dc2cd55a06fb3bc03827ce Mon Sep 17 00:00:00 2001 From: Liam Peters Date: Mon, 12 Jan 2026 13:21:43 +0000 Subject: [PATCH 2/3] Replace HashtableAst.SafeGetValue() compatibility shim with actual implementation --- Engine/Settings.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Engine/Settings.cs b/Engine/Settings.cs index b0c424c64..124e5488a 100644 --- a/Engine/Settings.cs +++ b/Engine/Settings.cs @@ -462,9 +462,7 @@ private void parseSettingsFile(string settingsFilePath) Hashtable hashtable; try { - // ideally we should use HashtableAst.SafeGetValue() but since - // it is not available on PSv3, we resort to our own narrow implementation. - hashtable = Helper.GetSafeValueFromHashtableAst(hashTableAst); + hashtable = (Hashtable) hashTableAst.SafeGetValue(); } catch (InvalidOperationException e) { From f094f2f7e4411d340a4aa9cfdcb2fb3113dd1fd5 Mon Sep 17 00:00:00 2001 From: Liam Peters Date: Mon, 12 Jan 2026 13:44:03 +0000 Subject: [PATCH 3/3] Remove/simplify conditional checks which would would always be met with a minimum version of 5.1 (no longer supporting v3 or v4) --- Engine/PSScriptAnalyzer.psm1 | 8 +- .../Documentation/RuleDocumentation.tests.ps1 | 6 - .../CommunityAnalyzerRules.psm1 | 307 +++++++++--------- Tests/Engine/CustomizedRule.tests.ps1 | 4 +- Tests/Engine/GetScriptAnalyzerRule.tests.ps1 | 14 +- Tests/Engine/Helper.tests.ps1 | 2 +- Tests/Engine/InvokeScriptAnalyzer.tests.ps1 | 6 +- .../Engine/ModuleDependencyHandler.tests.ps1 | 11 +- Tests/Engine/ModuleHelp.Tests.ps1 | 13 +- Tests/Engine/RuleSuppression.tests.ps1 | 2 +- Tests/Engine/RuleSuppressionClass.tests.ps1 | 17 +- .../Rules/AlignAssignmentStatement.tests.ps1 | 26 +- Tests/Rules/AvoidGlobalAliases.tests.ps1 | 8 +- Tests/Rules/DscExamplesPresent.tests.ps1 | 2 +- Tests/Rules/DscTestsPresent.tests.ps1 | 2 +- Tests/Rules/PSCredentialType.tests.ps1 | 3 - Tests/Rules/ProvideCommentHelp.tests.ps1 | 6 +- ...eturnCorrectTypesForDSCFunctions.tests.ps1 | 9 +- Tests/Rules/UseCompatibleSyntax.Tests.ps1 | 22 +- Tests/Rules/UseDSCResourceFunctions.tests.ps1 | 10 +- .../Rules/UseIdenticalParametersDSC.tests.ps1 | 14 +- Tests/Rules/UseOutputTypeCorrectly.tests.ps1 | 11 +- .../Rules/UseShouldProcessCorrectly.tests.ps1 | 6 +- build.psm1 | 16 +- 24 files changed, 210 insertions(+), 315 deletions(-) diff --git a/Engine/PSScriptAnalyzer.psm1 b/Engine/PSScriptAnalyzer.psm1 index 6d2563a49..acd9daf76 100644 --- a/Engine/PSScriptAnalyzer.psm1 +++ b/Engine/PSScriptAnalyzer.psm1 @@ -19,16 +19,10 @@ if ($PSVersionTable.PSVersion.Major -ge 6) { if ($PSVersionTable.PSVersion -lt $minimumPowerShellCoreVersion) { throw "Minimum supported version of PSScriptAnalyzer for PowerShell Core is $minimumPowerShellCoreVersion but current version is '$($PSVersionTable.PSVersion)'. Please update PowerShell Core." } -} -elseif ($PSVersionTable.PSVersion.Major -eq 5) { +} else { # Without this, PSSA tries to load this from $PSHome Add-Type -Path "$PSScriptRoot/Newtonsoft.Json.dll" } -elseif ($PSVersionTable.PSVersion.Major -le 4) { - $binaryModuleRoot = Join-Path -Path $PSModuleRoot -ChildPath "PSv$($PSVersionTable.PSVersion.Major)" - # Without this, PSSA tries to load this from $PSHome - Add-Type -Path "$binaryModuleRoot/Newtonsoft.Json.dll" -} $binaryModulePath = Join-Path -Path $binaryModuleRoot -ChildPath 'Microsoft.Windows.PowerShell.ScriptAnalyzer.dll' $binaryModule = Import-Module -Name $binaryModulePath -PassThru diff --git a/Tests/Documentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1 index a62c8506e..d8779af4f 100644 --- a/Tests/Documentation/RuleDocumentation.tests.ps1 +++ b/Tests/Documentation/RuleDocumentation.tests.ps1 @@ -15,12 +15,6 @@ Describe "Validate rule documentation files" { }} | Sort-Object - # Remove rules from the diff list that aren't supported on old PS version - if ($PSVersionTable.PSVersion.Major -eq 4) { - $docs = $docs | Where-Object {$_ -notmatch '^PSAvoidGlobalAliases$'} - $readmeRules = $readmeRules | Where-Object { $_ -notmatch '^PSAvoidGlobalAliases$' } - } - $rulesDocsDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $docs -SyncWindow 25 $rulesReadmeDiff = Compare-Object -ReferenceObject $rules -DifferenceObject $readmeRules -SyncWindow 25 } diff --git a/Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1 b/Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1 index f9abf9950..c28d80ec8 100644 --- a/Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1 +++ b/Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1 @@ -232,165 +232,158 @@ function Measure-RequiresModules } } +<# +.SYNOPSIS + You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script. +.DESCRIPTION + When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script. + To fix a violation of this rule, please store the type name in a variable or using -f operator. For example: + $namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue") +.EXAMPLE + Measure-LongClassName -CommandAst $CommandAst +.INPUTS + [System.Management.Automation.Language.CommandAst] +.OUTPUTS + [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] +.NOTES + Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition +#> +function Measure-LongClassName +{ + [CmdletBinding()] + [OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] + Param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.Language.CommandAst] + $CommandAst + ) + + Process + { + $results = @() + + # The StaticParameterBinder help us to find the argument of TypeName. + $spBinder = [System.Management.Automation.Language.StaticParameterBinder] + + # Checks New-Object without ComObject parameter command only. + if ($null -ne $CommandAst.GetCommandName()) + { + if ($CommandAst.GetCommandName() -ne "new-object") + { + return $results + } + } + else + { + return $results + } + + try + { + [System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true) + foreach ($sbResult in $sbResults) + { + # TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject. + if ($null -eq $sbResult.BoundParameters["TypeName"].ConstantValue) { continue } + + if ($sbResult.BoundParameters["TypeName"].ConstantValue.ToString().Split('.').Length -ge 3) + { + # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent. + $result = New-Object ` + -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" ` + -ArgumentList $Messages.MeasureLongClassName,$sbResult.BoundParameters["TypeName"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Information,$null + + $results += $result + } + } + + return $results + } + catch + { + $PSCmdlet.ThrowTerminatingError($PSItem) + } + + + } +} -# The two rules in the following if block use StaticParameterBinder class. -# StaticParameterBinder class was introduced in PSv4. -if ($PSVersionTable.PSVersion -ge [Version]'4.0.0') +<# +.SYNOPSIS + Please do not use COM objects when calling New-Object. +.DESCRIPTION + If you can't use just PowerShell, use .NET, external commands or COM objects, in that order of preference. COM objects are rarely well-documented, making them harder for someone else to research and understand. + They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect. + To fix a violation of this rule, please do not use COM objects when calling New-Object. +.EXAMPLE + Measure-ComObject -CommandAst $CommandAst +.INPUTS + [System.Management.Automation.Language.CommandAst] +.OUTPUTS + [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] +.NOTES + Reference: The Purity Laws, The Community Book of PowerShell Practices. +#> +function Measure-ComObject { - <# - .SYNOPSIS - You can store the type name in a variable or using -f operator to reduce the amount of redundant information in your script. - .DESCRIPTION - When interacting with classes that have long type names, you want to reduce the amount of redundant information in your script. - To fix a violation of this rule, please store the type name in a variable or using -f operator. For example: - $namespace = "System.Collections.{0}"; $arrayList = New-Object ($namespace -f "ArrayList"); $queue = New-Object ($namespace -f "Queue") - .EXAMPLE - Measure-LongClassName -CommandAst $CommandAst - .INPUTS - [System.Management.Automation.Language.CommandAst] - .OUTPUTS - [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES - Reference: 3.11. Reduce Typying for Long Class Names, Windows PowerShell Cookbook, Third Edition - #> - function Measure-LongClassName - { - [CmdletBinding()] - [OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] - Param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.Language.CommandAst] - $CommandAst - ) - - Process - { - $results = @() - - # The StaticParameterBinder help us to find the argument of TypeName. - $spBinder = [System.Management.Automation.Language.StaticParameterBinder] - - # Checks New-Object without ComObject parameter command only. - if ($null -ne $CommandAst.GetCommandName()) - { - if ($CommandAst.GetCommandName() -ne "new-object") - { - return $results - } - } - else - { - return $results - } - - try - { - [System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true) - foreach ($sbResult in $sbResults) - { - # TypeName cannot be found if user run command like, New-Object -ComObject Scripting.FileSystemObject. - if ($null -eq $sbResult.BoundParameters["TypeName"].ConstantValue) { continue } - - if ($sbResult.BoundParameters["TypeName"].ConstantValue.ToString().Split('.').Length -ge 3) - { - # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent. - $result = New-Object ` - -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" ` - -ArgumentList $Messages.MeasureLongClassName,$sbResult.BoundParameters["TypeName"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Information,$null - - $results += $result - } - } - - return $results - } - catch - { - $PSCmdlet.ThrowTerminatingError($PSItem) - } - - - } - } - - <# - .SYNOPSIS - Please do not use COM objects when calling New-Object. - .DESCRIPTION - If you can't use just PowerShell, use .NET, external commands or COM objects, in that order of preference. COM objects are rarely well-documented, making them harder for someone else to research and understand. - They do not always work flawlessly in PowerShell, as they must be used through .NET's Interop layer, which isn't 100% perfect. - To fix a violation of this rule, please do not use COM objects when calling New-Object. - .EXAMPLE - Measure-ComObject -CommandAst $CommandAst - .INPUTS - [System.Management.Automation.Language.CommandAst] - .OUTPUTS - [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]] - .NOTES - Reference: The Purity Laws, The Community Book of PowerShell Practices. - #> - function Measure-ComObject - { - [CmdletBinding()] - [OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] - Param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.Language.CommandAst] - $CommandAst - ) - - Process - { - $results = @() - - # The StaticParameterBinder help us to find the argument of TypeName. - $spBinder = [System.Management.Automation.Language.StaticParameterBinder] - - # Checks New-Object without ComObject parameter command only. - if ($null -ne $CommandAst.GetCommandName()) - { - if ($CommandAst.GetCommandName() -ne "new-object") - { - return $results - } - } - else - { - return $results - } - - try - { - [System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true) - foreach ($sbResult in $sbResults) - { - if ($sbResults.BoundParameters.ContainsKey("ComObject")) - { - # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent. - $result = New-Object ` - -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" ` - -ArgumentList $Messages.MeasureComObject,$sbResult.BoundParameters["ComObject"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null - - $results += $result - } - } - - return $results - } - catch - { - $PSCmdlet.ThrowTerminatingError($PSItem) - } - - - } - } - -} # end if ($PSVersionTable.PSVersion -ge [Version]'4.0') + [CmdletBinding()] + [OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] + Param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.Language.CommandAst] + $CommandAst + ) + + Process + { + $results = @() + + # The StaticParameterBinder help us to find the argument of TypeName. + $spBinder = [System.Management.Automation.Language.StaticParameterBinder] + + # Checks New-Object without ComObject parameter command only. + if ($null -ne $CommandAst.GetCommandName()) + { + if ($CommandAst.GetCommandName() -ne "new-object") + { + return $results + } + } + else + { + return $results + } + + try + { + [System.Management.Automation.Language.StaticBindingResult]$sbResults = $spBinder::BindCommand($CommandAst, $true) + foreach ($sbResult in $sbResults) + { + if ($sbResults.BoundParameters.ContainsKey("ComObject")) + { + # $sbResult.BoundParameters["TypeName"].Value is a CommandElementAst, so we can return an extent. + $result = New-Object ` + -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" ` + -ArgumentList $Messages.MeasureComObject,$sbResult.BoundParameters["ComObject"].Value.Extent,$PSCmdlet.MyInvocation.InvocationName,Warning,$null + + $results += $result + } + } + + return $results + } + catch + { + $PSCmdlet.ThrowTerminatingError($PSItem) + } + + + } +} <# diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index ba0686d75..ce60f6dce 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -257,7 +257,7 @@ Describe "Test importing correct customized rules" { $customizedRulePath.Count | Should -Be 1 } - It "loads custom rules that contain version in their path" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "loads custom rules that contain version in their path" { $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomRulePath $PSScriptRoot\VersionedSampleRule\SampleRuleWithVersion $customizedRulePath.Count | Should -Be 1 @@ -265,7 +265,7 @@ Describe "Test importing correct customized rules" { $customizedRulePath.Count | Should -Be 1 } - It "loads custom rules that contain version in their path with the RecurseCustomRule switch" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "loads custom rules that contain version in their path with the RecurseCustomRule switch" { $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomRulePath $PSScriptRoot\VersionedSampleRule -RecurseCustomRulePath $customizedRulePath.Count | Should -Be 1 diff --git a/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 b/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 index c3b744803..8dca8dcdc 100644 --- a/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 +++ b/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 @@ -64,14 +64,6 @@ Describe "Test Name parameters" { It "get Rules with no parameters supplied" { $defaultRules = Get-ScriptAnalyzerRule $expectedNumRules = 71 - if ($PSVersionTable.PSVersion.Major -le 4) - { - # for PSv3 PSAvoidGlobalAliases is not shipped because - # it uses StaticParameterBinder.BindCommand which is - # available only on PSv4 and above - - $expectedNumRules-- - } $defaultRules.Count | Should -Be $expectedNumRules } @@ -100,11 +92,7 @@ Describe "Test RuleExtension" { BeforeAll { $community = "CommunityAnalyzerRules" $measureRequired = "Measure-RequiresModules" - $expectedNumCommunityRules = 10 - if ($PSVersionTable.PSVersion -ge [Version]'4.0.0') - { - $expectedNumCommunityRules = 12 - } + $expectedNumCommunityRules = 12 } It "with the module folder path" { $ruleExtension = Get-ScriptAnalyzerRule -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules | Where-Object {$_.SourceName -eq $community} diff --git a/Tests/Engine/Helper.tests.ps1 b/Tests/Engine/Helper.tests.ps1 index b0932be32..3d53e71f1 100644 --- a/Tests/Engine/Helper.tests.ps1 +++ b/Tests/Engine/Helper.tests.ps1 @@ -33,7 +33,7 @@ Describe "Test Directed Graph" { } Context "Runspaces should be disposed" { - It "Running analyzer 100 times should only create a limited number of runspaces" -Skip:$($PSVersionTable.PSVersion.Major -le 4) { + It "Running analyzer 100 times should only create a limited number of runspaces" { $null = 1..100 | ForEach-Object { Invoke-ScriptAnalyzer -ScriptDefinition 'gci' } (Get-Runspace).Count | Should -BeLessOrEqual 14 -Because 'Number of Runspaces should be bound (size of runspace pool cache is 10)' } diff --git a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 index b930c9980..980836218 100644 --- a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 +++ b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 @@ -71,7 +71,7 @@ Describe "Test available parameters" { } } - Context "SaveDscDependency parameter" -Skip:($testingLibraryUsage -or ($PSVersionTable.PSVersion -lt '5.0')) { + Context "SaveDscDependency parameter" -Skip:($testingLibraryUsage) { It "has the parameter" { $params.ContainsKey("SaveDscDependency") | Should -BeTrue } @@ -616,7 +616,7 @@ Describe "-ReportSummary switch" { } # using statements are only supported in v5+ -Describe "Handles parse errors due to unknown types" -Skip:($testingLibraryUsage -or ($PSVersionTable.PSVersion -lt '5.0')) { +Describe "Handles parse errors due to unknown types" -Skip:($testingLibraryUsage) { BeforeAll { $script = @' using namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels @@ -640,7 +640,7 @@ Describe "Handles parse errors due to unknown types" -Skip:($testingLibraryUsage } } -Describe 'Handles static Singleton (issue 1182)' -Skip:($testingLibraryUsage -or ($PSVersionTable.PSVersion -lt '5.0')) { +Describe 'Handles static Singleton (issue 1182)' -Skip:($testingLibraryUsage) { It 'Does not throw or return diagnostic record' { $scriptDefinition = 'class T { static [T]$i }; function foo { [CmdletBinding()] param () $script:T.WriteLog() }' Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -ErrorAction Stop | Should -BeNullOrEmpty diff --git a/Tests/Engine/ModuleDependencyHandler.tests.ps1 b/Tests/Engine/ModuleDependencyHandler.tests.ps1 index 09bd74912..92735fb9e 100644 --- a/Tests/Engine/ModuleDependencyHandler.tests.ps1 +++ b/Tests/Engine/ModuleDependencyHandler.tests.ps1 @@ -3,7 +3,7 @@ function Get-Skip { - if ($testingLibararyUsage -or ($PSVersionTable.PSVersion -lt '5.0')) + if ($testingLibararyUsage) { return $true } @@ -50,7 +50,6 @@ Describe "Resolve DSC Resource Dependency" { Context "Module handler class" { BeforeAll { - if ($PSVersionTable.PSVersion -lt '5.0') { return } $moduleHandlerType = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.ModuleDependencyHandler] $oldEnvVars = Get-Item Env:\* | Sort-Object -Property Key $savedPSModulePath = $env:PSModulePath @@ -59,7 +58,7 @@ Describe "Resolve DSC Resource Dependency" { if ( $skipTest ) { return } $env:PSModulePath = $savedPSModulePath } - It "Sets defaults correctly" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "Sets defaults correctly" { $rsp = [runspacefactory]::CreateRunspace() $rsp.Open() $depHandler = $moduleHandlerType::new($rsp) @@ -82,15 +81,15 @@ Describe "Resolve DSC Resource Dependency" { $rsp.Dispose() } - It "Keeps the environment variables unchanged" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "Keeps the environment variables unchanged" { Test-EnvironmentVariables($oldEnvVars) } - It "Throws if runspace is null" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "Throws if runspace is null" { {$moduleHandlerType::new($null)} | Should -Throw } - It "Throws if runspace is not opened" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "Throws if runspace is not opened" { $rsp = [runspacefactory]::CreateRunspace() {$moduleHandlerType::new($rsp)} | Should -Throw $rsp.Dispose() diff --git a/Tests/Engine/ModuleHelp.Tests.ps1 b/Tests/Engine/ModuleHelp.Tests.ps1 index ac40dcf94..21188e019 100644 --- a/Tests/Engine/ModuleHelp.Tests.ps1 +++ b/Tests/Engine/ModuleHelp.Tests.ps1 @@ -62,14 +62,8 @@ $paramBlockList = @( 'AttachAndDebug' # Reason: When building with DEGUG configuration, an additional parameter 'AttachAndDebug' will be added to Invoke-ScriptAnalyzer and Invoke-Formatter, but there is no Help for those, as they are not intended for production usage. ) [string] $ModuleName = 'PSScriptAnalyzer' -if ($PSVersionTable.PSVersion -lt '5.0') { - $ms = New-Object -TypeName 'Microsoft.PowerShell.Commands.ModuleSpecification' -ArgumentList $ModuleName - $commands = Get-Command -Module $ms.Name -} -else { - $ms = [Microsoft.PowerShell.Commands.ModuleSpecification]@{ ModuleName = $ModuleName; RequiredVersion = $RequiredVersion } - $commands = Get-Command -FullyQualifiedModule $ms -} +$ms = [Microsoft.PowerShell.Commands.ModuleSpecification]@{ ModuleName = $ModuleName; RequiredVersion = $RequiredVersion } +$commands = Get-Command -FullyQualifiedModule $ms $testCases = $commands.ForEach{ @{ @@ -92,9 +86,6 @@ BeforeAll { $paramBlockList = @( 'AttachAndDebug' # Reason: When building with DEGUG configuration, an additional parameter 'AttachAndDebug' will be added to Invoke-ScriptAnalyzer and Invoke-Formatter, but there is no Help for those, as they are not intended for production usage. ) - if ($PSVersionTable.PSVersion -lt '5.0') { - $paramBlockList += 'SaveDscDependency' - } } diff --git a/Tests/Engine/RuleSuppression.tests.ps1 b/Tests/Engine/RuleSuppression.tests.ps1 index 2d81f6305..2d31a6ddf 100644 --- a/Tests/Engine/RuleSuppression.tests.ps1 +++ b/Tests/Engine/RuleSuppression.tests.ps1 @@ -404,7 +404,7 @@ function Allow-GetFooBar { } Context "Rule suppression within DSC Configuration definition" { - It "Suppresses rule" -Skip:($IsLinux -or $IsMacOS -or ($PSVersionTable.PSVersion.Major -lt 5)) { + It "Suppresses rule" -Skip:($IsLinux -or $IsMacOS) { $suppressedRule = Invoke-ScriptAnalyzer -ScriptDefinition $ruleSuppressionInConfiguration -SuppressedOnly $suppressedRule.Count | Should -Be 1 } diff --git a/Tests/Engine/RuleSuppressionClass.tests.ps1 b/Tests/Engine/RuleSuppressionClass.tests.ps1 index 28c3aad22..22dc8e333 100644 --- a/Tests/Engine/RuleSuppressionClass.tests.ps1 +++ b/Tests/Engine/RuleSuppressionClass.tests.ps1 @@ -2,11 +2,6 @@ # Licensed under the MIT License. BeforeAll { - $script:skipForV3V4 = $true - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') { - $script:skipForV3V4 = $false - } - $violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\RuleSuppression.ps1") $violations = Invoke-ScriptAnalyzer "$PSScriptRoot\RuleSuppression.ps1" } @@ -14,7 +9,7 @@ BeforeAll { Describe "RuleSuppressionWithoutScope" { Context "Class" { - It "Does not raise violations" -skip:$script:skipForV3V4 { + It "Does not raise violations" { $suppression = $violations | Where-Object {$_.RuleName -eq "PSAvoidUsingInvokeExpression" } $suppression.Count | Should -Be 0 $suppression = $violationsUsingScriptDefinition | Where-Object {$_.RuleName -eq "PSAvoidUsingInvokeExpression" } @@ -23,7 +18,7 @@ Describe "RuleSuppressionWithoutScope" { } Context "FunctionInClass" { - It "Does not raise violations" -skip:$script:skipForV3V4 { + It "Does not raise violations" { $suppression = $violations | Where-Object {$_.RuleName -eq "PSAvoidUsingCmdletAliases" } $suppression.Count | Should -Be 0 $suppression = $violationsUsingScriptDefinition | Where-Object {$_.RuleName -eq "PSAvoidUsingCmdletAliases" } @@ -32,7 +27,7 @@ Describe "RuleSuppressionWithoutScope" { } Context "Script" { - It "Does not raise violations" -skip:$script:skipForV3V4 { + It "Does not raise violations" { $suppression = $violations | Where-Object {$_.RuleName -eq "PSProvideCommentHelp" } $suppression.Count | Should -Be 0 $suppression = $violationsUsingScriptDefinition | Where-Object {$_.RuleName -eq "PSProvideCommentHelp" } @@ -41,7 +36,7 @@ Describe "RuleSuppressionWithoutScope" { } Context "RuleSuppressionID" { - It "Only suppress violations for that ID" -skip:$script:skipForV3V4 { + It "Only suppress violations for that ID" { $suppression = $violations | Where-Object {$_.RuleName -eq "PSAvoidDefaultValueForMandatoryParameter" } $suppression.Count | Should -Be 1 $suppression = $violationsUsingScriptDefinition | Where-Object {$_.RuleName -eq "PSAvoidDefaultValueForMandatoryParameter" } @@ -52,7 +47,7 @@ Describe "RuleSuppressionWithoutScope" { Describe "RuleSuppressionWithScope" { Context "FunctionScope" { - It "Does not raise violations" -skip:$script:skipForV3V4 { + It "Does not raise violations" { $suppression = $violations | Where-Object {$_.RuleName -eq "PSAvoidUsingPositionalParameters" } $suppression.Count | Should -Be 0 $suppression = $violationsUsingScriptDefinition | Where-Object {$_.RuleName -eq "PSAvoidUsingPositionalParameters" } @@ -61,7 +56,7 @@ Describe "RuleSuppressionWithScope" { } Context "ClassScope" { - It "Does not raise violations" -skip:$script:skipForV3V4 { + It "Does not raise violations" { $suppression = $violations | Where-Object {$_.RuleName -eq "PSAvoidUsingConvertToSecureStringWithPlainText" } $suppression.Count | Should -Be 0 $suppression = $violationsUsingScriptDefinition | Where-Object {$_.RuleName -eq "PSAvoidUsingConvertToSecureStringWithPlainText" } diff --git a/Tests/Rules/AlignAssignmentStatement.tests.ps1 b/Tests/Rules/AlignAssignmentStatement.tests.ps1 index 7558abf88..f252cccb5 100644 --- a/Tests/Rules/AlignAssignmentStatement.tests.ps1 +++ b/Tests/Rules/AlignAssignmentStatement.tests.ps1 @@ -86,8 +86,8 @@ $x = @{ 'key'="value" } It "Should ignore if a hashtable has a single key-value pair across multiple lines" { $def = @' -$x = @{ - 'key'="value" +$x = @{ + 'key'="value" } '@ Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Get-Count | Should -Be 0 @@ -128,10 +128,9 @@ Configuration MyDscConfiguration { } } - if ($PSVersionTable.PSVersion.Major -ge 5) { - Context "When assignment statements are in DSC Configuration that has parse errors" { - It "Should find violations when assignment statements are not aligned" -skip:($IsLinux -or $IsMacOS) { - $def = @' + Context "When assignment statements are in DSC Configuration that has parse errors" { + It "Should find violations when assignment statements are not aligned" -skip:($IsLinux -or $IsMacOS) { + $def = @' Configuration Sample_ChangeDescriptionAndPermissions { Import-DscResource -Module NonExistentModule @@ -152,14 +151,13 @@ Configuration Sample_ChangeDescriptionAndPermissions } } '@ - # This invocation will throw parse error caused by "Undefined DSC resource" because - # NonExistentModule is not really avaiable to load. Therefore we set erroraction to - # SilentlyContinue - Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings -ErrorAction SilentlyContinue | - Where-Object { $_.Severity -ne "ParseError" } | - Get-Count | - Should -Be 4 - } + # This invocation will throw parse error caused by "Undefined DSC resource" because + # NonExistentModule is not really avaiable to load. Therefore we set erroraction to + # SilentlyContinue + Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings -ErrorAction SilentlyContinue | + Where-Object { $_.Severity -ne "ParseError" } | + Get-Count | + Should -Be 4 } } } diff --git a/Tests/Rules/AvoidGlobalAliases.tests.ps1 b/Tests/Rules/AvoidGlobalAliases.tests.ps1 index e57b00446..bfb1c4e0d 100644 --- a/Tests/Rules/AvoidGlobalAliases.tests.ps1 +++ b/Tests/Rules/AvoidGlobalAliases.tests.ps1 @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -$IsV3OrV4 = ($PSVersionTable.PSVersion.Major -eq 3) -or ($PSVersionTable.PSVersion.Major -eq 4) - BeforeAll { $AvoidGlobalAliasesError = "Avoid creating aliases with a Global scope." $violationName = "PSAvoidGlobalAliases" @@ -12,17 +10,17 @@ BeforeAll { Describe "$violationName " { Context "When there are violations" { - It "Has 4 avoid global alias violations" -Skip:$IsV3OrV4 { + It "Has 4 avoid global alias violations" { $violations.Count | Should -Be 4 } - It "Has the correct description message" -Skip:$IsV3OrV4 { + It "Has the correct description message" { $violations[0].Message | Should -Match $AvoidGlobalAliasesError } } Context "When there are no violations" { - It "Returns no violations" -Skip:$IsV3OrV4 { + It "Returns no violations" { $noViolations.Count | Should -Be 0 } } diff --git a/Tests/Rules/DscExamplesPresent.tests.ps1 b/Tests/Rules/DscExamplesPresent.tests.ps1 index fd98c00dd..e4dc8e547 100644 --- a/Tests/Rules/DscExamplesPresent.tests.ps1 +++ b/Tests/Rules/DscExamplesPresent.tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $ruleName = "PSDSCDscExamplesPresent" } - Describe "DscExamplesPresent rule in class based resource" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + Describe "DscExamplesPresent rule in class based resource" { BeforeAll { $examplesPath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\Examples" $classResourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1" diff --git a/Tests/Rules/DscTestsPresent.tests.ps1 b/Tests/Rules/DscTestsPresent.tests.ps1 index b81104d1d..e49e80623 100644 --- a/Tests/Rules/DscTestsPresent.tests.ps1 +++ b/Tests/Rules/DscTestsPresent.tests.ps1 @@ -5,7 +5,7 @@ BeforeAll { $ruleName = "PSDSCDscTestsPresent" } - Describe "DscTestsPresent rule in class based resource" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + Describe "DscTestsPresent rule in class based resource" { BeforeAll { $testsPath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\Tests" $classResourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1" diff --git a/Tests/Rules/PSCredentialType.tests.ps1 b/Tests/Rules/PSCredentialType.tests.ps1 index ceb04e3ee..4aa2c35a7 100644 --- a/Tests/Rules/PSCredentialType.tests.ps1 +++ b/Tests/Rules/PSCredentialType.tests.ps1 @@ -12,9 +12,6 @@ Describe "PSCredentialType" { Context "When there are violations" { BeforeAll { $expectedViolations = 1 - if (($PSVersionTable.PSVersion.Major -eq 3) -or ($PSVersionTable.PSVersion.Major -eq 4)) { - $expectedViolations = 2 - } } It ("has correct count of PSCredential type violations" -f $expectedViolations) { $violations.Count | Should -Be $expectedViolations diff --git a/Tests/Rules/ProvideCommentHelp.tests.ps1 b/Tests/Rules/ProvideCommentHelp.tests.ps1 index 2216f15f0..f0900b07d 100644 --- a/Tests/Rules/ProvideCommentHelp.tests.ps1 +++ b/Tests/Rules/ProvideCommentHelp.tests.ps1 @@ -22,9 +22,7 @@ BeforeAll { $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName} - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') { - $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - } + $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName} @@ -334,7 +332,7 @@ $s$s$s$s } - It "Does not count violation in DSC class" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + It "Does not count violation in DSC class" { $dscViolations.Count | Should -Be 0 } } diff --git a/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1 b/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1 index 1ed4f610f..fc10ae39c 100644 --- a/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1 +++ b/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1 @@ -8,11 +8,8 @@ BeforeAll { $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName} $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName} - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') - { - $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - } + $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} + $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} } Describe "ReturnCorrectTypesForDSCFunctions" { @@ -33,7 +30,7 @@ Describe "ReturnCorrectTypesForDSCFunctions" { } } - Describe "StandardDSCFunctionsInClass" -Skip:($PSVersionTable.PSVersion -lt '5.0') { + Describe "StandardDSCFunctionsInClass" { Context "When there are violations" { It "has 4 return correct types for DSC functions violations" { $classViolations.Count | Should -Be 4 diff --git a/Tests/Rules/UseCompatibleSyntax.Tests.ps1 b/Tests/Rules/UseCompatibleSyntax.Tests.ps1 index 64ac464ae..263adf8a8 100644 --- a/Tests/Rules/UseCompatibleSyntax.Tests.ps1 +++ b/Tests/Rules/UseCompatibleSyntax.Tests.ps1 @@ -12,15 +12,10 @@ BeforeDiscovery { @{ Script = '$y.$methodWithAVeryLongName()'; Versions = @(3) } @{ Script = '$typeExpression::$staticMember'; Versions = @() } @{ Script = '$typeExpression::$dynamicStaticMethodName()'; Versions = @(3) } + @{ Script = "class MyClass { }"; Versions = @(3,4) } + @{ Script = "enum MyEnum { One; Two }"; Versions = @(3,4) } ) - # PS v3/4 won't parse classes or enums - if ($PSVersionTable.PSVersion.Major -ge 5) - { - $testCases += @( - @{ Script = "class MyClass { }"; Versions = @(3,4) } - @{ Script = "enum MyEnum { One; Two }"; Versions = @(3,4) } - ) - } + # PS v6+ won't parse workflows if ($PSVersionTable.PSVersion.Major -le 5) { @@ -79,16 +74,7 @@ Describe "PSUseCompatibleSyntax" { $diagnostics = Invoke-ScriptAnalyzer -IncludeRule PSUseCompatibleSyntax -Path "$PSScriptRoot/CompatibilityRuleAssets/IncompatibleScript.ps1" -Settings $settings ` | Where-Object { $_.RuleName -eq 'PSUseCompatibleSyntax' } - if ($PSVersionTable.PSVersion.Major -ge 5) - { - $expected = 5 - } - else - { - # PSv3/4 can't detect class/enum parts - $expected = 4 - } - + $expected = 5 $diagnostics.Count | Should -Be $expected } diff --git a/Tests/Rules/UseDSCResourceFunctions.tests.ps1 b/Tests/Rules/UseDSCResourceFunctions.tests.ps1 index 2efc16ec0..9112d6e22 100644 --- a/Tests/Rules/UseDSCResourceFunctions.tests.ps1 +++ b/Tests/Rules/UseDSCResourceFunctions.tests.ps1 @@ -7,12 +7,8 @@ BeforeAll { $violationName = "PSDSCStandardDSCFunctionsInResource" $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName} $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName} - - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') - { - $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - } + $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} + $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} } @@ -34,7 +30,7 @@ Describe "StandardDSCFunctionsInResource" { } } -Describe "StandardDSCFunctionsInClass" -Skip:($PSVersionTable.PSVersion -lt '5.0') { +Describe "StandardDSCFunctionsInClass" { Context "When there are violations" { It "has 1 missing standard DSC functions violation" { $classViolations.Count | Should -Be 1 diff --git a/Tests/Rules/UseIdenticalParametersDSC.tests.ps1 b/Tests/Rules/UseIdenticalParametersDSC.tests.ps1 index c47a2bf56..622105087 100644 --- a/Tests/Rules/UseIdenticalParametersDSC.tests.ps1 +++ b/Tests/Rules/UseIdenticalParametersDSC.tests.ps1 @@ -6,11 +6,7 @@ BeforeAll { $violationName = "PSDSCUseIdenticalParametersForDSC" $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName} $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName} - - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') - { - $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - } + $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} } @@ -30,12 +26,8 @@ Describe "UseIdenticalParametersDSC" { $noViolations.Count | Should -Be 0 } - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') - { - - It "returns no violations for DSC Classes" { - $noClassViolations.Count | Should -Be 0 - } + It "returns no violations for DSC Classes" { + $noClassViolations.Count | Should -Be 0 } } } diff --git a/Tests/Rules/UseOutputTypeCorrectly.tests.ps1 b/Tests/Rules/UseOutputTypeCorrectly.tests.ps1 index 8cc657e0b..fa1087847 100644 --- a/Tests/Rules/UseOutputTypeCorrectly.tests.ps1 +++ b/Tests/Rules/UseOutputTypeCorrectly.tests.ps1 @@ -5,10 +5,7 @@ BeforeAll { $violationMessage = "The cmdlet 'Verb-Files' returns an object of type 'System.Collections.Hashtable' but this type is not declared in the OutputType attribute." $violationName = "PSUseOutputTypeCorrectly" $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName} - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') - { - $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} - } + $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName} $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName} } @@ -23,10 +20,8 @@ Describe "UseOutputTypeCorrectly" { $violations[1].Message | Should -Match $violationMessage } - if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') { - It "Does not count violation in DSC class" { - $dscViolations.Count | Should -Be 0 - } + It "Does not count violation in DSC class" { + $dscViolations.Count | Should -Be 0 } } diff --git a/Tests/Rules/UseShouldProcessCorrectly.tests.ps1 b/Tests/Rules/UseShouldProcessCorrectly.tests.ps1 index 2c0314f70..ed5b5e084 100644 --- a/Tests/Rules/UseShouldProcessCorrectly.tests.ps1 +++ b/Tests/Rules/UseShouldProcessCorrectly.tests.ps1 @@ -1,8 +1,6 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -$IsV3OrV4 = ($PSVersionTable.PSVersion.Major -eq 3) -or ($PSVersionTable.PSVersion.Major -eq 4) - BeforeAll { $violationMessage = "'Verb-Files' has the ShouldProcess attribute but does not call ShouldProcess/ShouldContinue." $violationName = "PSShouldProcess" @@ -179,7 +177,7 @@ function Remove-Foo { } # Install-Module is present by default only on PSv5 and above - It "finds no violation when caller declares SupportsShouldProcess and callee is a function with ShouldProcess" -Skip:$IsV3OrV4 { + It "finds no violation when caller declares SupportsShouldProcess and callee is a function with ShouldProcess" { $scriptDef = @' function Install-Foo { [CmdletBinding(SupportsShouldProcess)] @@ -231,7 +229,7 @@ function Install-ModuleWithDeps { } # Install-Module is present by default only on PSv5 and above - It "finds no violation for a function with self reference and implicit call to ShouldProcess" -Skip:$IsV3OrV4 { + It "finds no violation for a function with self reference and implicit call to ShouldProcess" { $scriptDef = @' function Install-ModuleWithDeps { [CmdletBinding(SupportsShouldProcess)] diff --git a/build.psm1 b/build.psm1 index 5daba36ba..041b207a9 100644 --- a/build.psm1 +++ b/build.psm1 @@ -317,20 +317,9 @@ function Test-ScriptAnalyzer # and ".../out/PSScriptAnalyzer" is added to env:PSModulePath # # - $major = $PSVersionTable.PSVersion.Major - if ( $major -lt 5 ) { - # get the directory name of the destination, we need to change it - $versionDirectoryRoot = Split-Path $script:destinationDir - $testModulePath = Join-Path $versionDirectoryRoot $analyzerName - } - else { - $testModulePath = Join-Path "${projectRoot}" -ChildPath out - } + $testModulePath = Join-Path "${projectRoot}" -ChildPath out $testScripts = "'${projectRoot}\Tests\Build','${projectRoot}\Tests\Engine','${projectRoot}\Tests\Rules','${projectRoot}\Tests\Documentation'" try { - if ( $major -lt 5 ) { - Rename-Item $script:destinationDir ${testModulePath} - } $savedModulePath = $env:PSModulePath $env:PSModulePath = "${testModulePath}{0}${env:PSModulePath}" -f [System.IO.Path]::PathSeparator $analyzerPsd1Path = Join-Path -Path $script:destinationDir -ChildPath "$analyzerName.psd1" @@ -353,9 +342,6 @@ function Test-ScriptAnalyzer } finally { $env:PSModulePath = $savedModulePath - if ( $major -lt 5 ) { - Rename-Item ${testModulePath} ${script:destinationDir} - } } } }