From cedb19b1eac2dec4f81739174a0d5a729263a1f6 Mon Sep 17 00:00:00 2001 From: Thomas Rayner Date: Wed, 16 Oct 2019 13:50:43 -0700 Subject: [PATCH] updates a/p rjmholt --- Rules/AvoidOverwritingBuiltInCmdlets.cs | 125 +++++++++++------------- 1 file changed, 57 insertions(+), 68 deletions(-) diff --git a/Rules/AvoidOverwritingBuiltInCmdlets.cs b/Rules/AvoidOverwritingBuiltInCmdlets.cs index e714f4a1b..6b7f669c1 100644 --- a/Rules/AvoidOverwritingBuiltInCmdlets.cs +++ b/Rules/AvoidOverwritingBuiltInCmdlets.cs @@ -29,44 +29,26 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules /// public class AvoidOverwritingBuiltInCmdlets : ConfigurableRule { + /// + /// Specify the version of PowerShell to compare against since different versions of PowerShell + /// ship with different sets of built in cmdlets. The default value for PowerShellVersion is + /// "core-6.1.0-windows" if PowerShell 6 or later is installed, and "desktop-5.1.14393.206-windows" + /// if it is not. The version specified aligns with a JSON file in `/path/to/PSScriptAnalyzerModule/Settings`. + /// These files are of the form, `PSEDITION-PSVERSION-OS.json` where `PSEDITION` can be either `Core` or + /// `Desktop`, `OS` can be either `Windows`, `Linux` or `MacOS`, and `Version` is the PowerShell version. + /// [ConfigurableRuleProperty(defaultValue: "")] public string[] PowerShellVersion { get; set; } - private Dictionary> cmdletMap; - private bool initialized; + private readonly Dictionary> _cmdletMap; /// /// Construct an object of AvoidOverwritingBuiltInCmdlets type. /// - public AvoidOverwritingBuiltInCmdlets() : base() + public AvoidOverwritingBuiltInCmdlets() { - initialized = false; - cmdletMap = new Dictionary>(); + _cmdletMap = new Dictionary>(); Enable = true; // Enable rule by default - - string versionTest = string.Join("", PowerShellVersion); - - if (versionTest != "core-6.1.0-windows" && versionTest != "desktop-5.1.14393.206-windows") - { - // PowerShellVersion is not already set to one of the acceptable defaults - // Try launching `pwsh -v` to see if PowerShell 6+ is installed, and use those cmdlets - // as a default. If 6+ is not installed this will throw an error, which when caught will - // allow us to use the PowerShell 5 cmdlets as a default. - try - { - var testProcess = new Process(); - testProcess.StartInfo.FileName = "pwsh"; - testProcess.StartInfo.Arguments = "-v"; - testProcess.StartInfo.CreateNoWindow = true; - testProcess.StartInfo.UseShellExecute = false; - testProcess.Start(); - PowerShellVersion = new[] {"core-6.1.0-windows"}; - } - catch - { - PowerShellVersion = new[] {"desktop-5.1.14393.206-windows"}; - } - } } @@ -83,7 +65,7 @@ public override IEnumerable AnalyzeScript(Ast ast, string file throw new ArgumentNullException(nameof(ast)); } - var functionDefinitions = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); + IEnumerable functionDefinitions = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true).OfType(); if (functionDefinitions.Count() < 1) { // There are no function definitions in this AST and so it's not worth checking the rest of this rule @@ -93,29 +75,61 @@ public override IEnumerable AnalyzeScript(Ast ast, string file else { var diagnosticRecords = new List(); - if (!initialized) + string versionTest = string.Join("", PowerShellVersion); + + if (string.IsNullOrEmpty(versionTest)) { - Initialize(); - if (!initialized) + // PowerShellVersion is not already set to one of the acceptable defaults + // Try launching `pwsh -v` to see if PowerShell 6+ is installed, and use those cmdlets + // as a default. If 6+ is not installed this will throw an error, which when caught will + // allow us to use the PowerShell 5 cmdlets as a default. + var testProcess = new Process(); + testProcess.StartInfo.FileName = "pwsh"; + testProcess.StartInfo.Arguments = "-v"; + testProcess.StartInfo.CreateNoWindow = true; + testProcess.StartInfo.UseShellExecute = false; + + try { - throw new Exception("Failed to initialize rule " + GetName()); + testProcess.Start(); + PowerShellVersion = new[] { "core-6.1.0-windows" }; + } + catch + { + PowerShellVersion = new[] { "desktop-5.1.14393.206-windows" }; + } + finally + { + testProcess.Dispose(); } } - foreach (var functionDef in functionDefinitions) + var psVerList = PowerShellVersion; + string settingsPath = Settings.GetShippedSettingsDirectory(); + + foreach (string reference in psVerList) { - FunctionDefinitionAst funcDef = functionDef as FunctionDefinitionAst; - if (funcDef == null) + if (settingsPath == null || !ContainsReferenceFile(settingsPath, reference)) { - continue; + throw new ArgumentException(nameof(PowerShellVersion)); } + } + + ProcessDirectory(settingsPath, psVerList); + + if (_cmdletMap.Keys.Count != psVerList.Count()) + { + throw new ArgumentException(nameof(PowerShellVersion)); + } - string functionName = funcDef.Name; - foreach (var map in cmdletMap) + foreach (FunctionDefinitionAst functionDef in functionDefinitions) + { + string functionName = functionDef.Name; + foreach (KeyValuePair> cmdletSet in _cmdletMap) { - if (map.Value.Contains(functionName)) + if (cmdletSet.Value.Contains(functionName)) { - diagnosticRecords.Add(CreateDiagnosticRecord(functionName, map.Key, functionDef.Extent)); + diagnosticRecords.Add(CreateDiagnosticRecord(functionName, cmdletSet.Key, functionDef.Extent)); } } } @@ -140,31 +154,6 @@ private DiagnosticRecord CreateDiagnosticRecord(string FunctionName, string PSVe } - private void Initialize() - { - var psVerList = PowerShellVersion; - - string settingsPath = Settings.GetShippedSettingsDirectory(); - - foreach (string reference in psVerList) - { - if (settingsPath == null || !ContainsReferenceFile(settingsPath, reference)) - { - return; - } - } - - ProcessDirectory(settingsPath, psVerList); - - if (cmdletMap.Keys.Count != psVerList.Count()) - { - return; - } - - initialized = true; - } - - private bool ContainsReferenceFile(string directory, string reference) { return File.Exists(Path.Combine(directory, reference + ".json")); @@ -189,7 +178,7 @@ private void ProcessDirectory(string path, IEnumerable acceptablePlatfor continue; } - cmdletMap.Add(fileNameWithoutExt, GetCmdletsFromData(JObject.Parse(File.ReadAllText(filePath)))); + _cmdletMap.Add(fileNameWithoutExt, GetCmdletsFromData(JObject.Parse(File.ReadAllText(filePath)))); } }