@@ -29,44 +29,26 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
2929 /// </summary>
3030 public class AvoidOverwritingBuiltInCmdlets : ConfigurableRule
3131 {
32+ /// <summary>
33+ /// Specify the version of PowerShell to compare against since different versions of PowerShell
34+ /// ship with different sets of built in cmdlets. The default value for PowerShellVersion is
35+ /// "core-6.1.0-windows" if PowerShell 6 or later is installed, and "desktop-5.1.14393.206-windows"
36+ /// if it is not. The version specified aligns with a JSON file in `/path/to/PSScriptAnalyzerModule/Settings`.
37+ /// These files are of the form, `PSEDITION-PSVERSION-OS.json` where `PSEDITION` can be either `Core` or
38+ /// `Desktop`, `OS` can be either `Windows`, `Linux` or `MacOS`, and `Version` is the PowerShell version.
39+ /// </summary>
3240 [ ConfigurableRuleProperty ( defaultValue : "" ) ]
3341 public string [ ] PowerShellVersion { get ; set ; }
34- private Dictionary < string , HashSet < string > > cmdletMap ;
35- private bool initialized ;
42+ private readonly Dictionary < string , HashSet < string > > _cmdletMap ;
3643
3744
3845 /// <summary>
3946 /// Construct an object of AvoidOverwritingBuiltInCmdlets type.
4047 /// </summary>
41- public AvoidOverwritingBuiltInCmdlets ( ) : base ( )
48+ public AvoidOverwritingBuiltInCmdlets ( )
4249 {
43- initialized = false ;
44- cmdletMap = new Dictionary < string , HashSet < string > > ( ) ;
50+ _cmdletMap = new Dictionary < string , HashSet < string > > ( ) ;
4551 Enable = true ; // Enable rule by default
46-
47- string versionTest = string . Join ( "" , PowerShellVersion ) ;
48-
49- if ( versionTest != "core-6.1.0-windows" && versionTest != "desktop-5.1.14393.206-windows" )
50- {
51- // PowerShellVersion is not already set to one of the acceptable defaults
52- // Try launching `pwsh -v` to see if PowerShell 6+ is installed, and use those cmdlets
53- // as a default. If 6+ is not installed this will throw an error, which when caught will
54- // allow us to use the PowerShell 5 cmdlets as a default.
55- try
56- {
57- var testProcess = new Process ( ) ;
58- testProcess . StartInfo . FileName = "pwsh" ;
59- testProcess . StartInfo . Arguments = "-v" ;
60- testProcess . StartInfo . CreateNoWindow = true ;
61- testProcess . StartInfo . UseShellExecute = false ;
62- testProcess . Start ( ) ;
63- PowerShellVersion = new [ ] { "core-6.1.0-windows" } ;
64- }
65- catch
66- {
67- PowerShellVersion = new [ ] { "desktop-5.1.14393.206-windows" } ;
68- }
69- }
7052 }
7153
7254
@@ -83,7 +65,7 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
8365 throw new ArgumentNullException ( nameof ( ast ) ) ;
8466 }
8567
86- var functionDefinitions = ast . FindAll ( testAst => testAst is FunctionDefinitionAst , true ) ;
68+ IEnumerable < FunctionDefinitionAst > functionDefinitions = ast . FindAll ( testAst => testAst is FunctionDefinitionAst , true ) . OfType < FunctionDefinitionAst > ( ) ;
8769 if ( functionDefinitions . Count ( ) < 1 )
8870 {
8971 // 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<DiagnosticRecord> AnalyzeScript(Ast ast, string file
9375 else
9476 {
9577 var diagnosticRecords = new List < DiagnosticRecord > ( ) ;
96- if ( ! initialized )
78+ string versionTest = string . Join ( "" , PowerShellVersion ) ;
79+
80+ if ( string . IsNullOrEmpty ( versionTest ) )
9781 {
98- Initialize ( ) ;
99- if ( ! initialized )
82+ // PowerShellVersion is not already set to one of the acceptable defaults
83+ // Try launching `pwsh -v` to see if PowerShell 6+ is installed, and use those cmdlets
84+ // as a default. If 6+ is not installed this will throw an error, which when caught will
85+ // allow us to use the PowerShell 5 cmdlets as a default.
86+ var testProcess = new Process ( ) ;
87+ testProcess . StartInfo . FileName = "pwsh" ;
88+ testProcess . StartInfo . Arguments = "-v" ;
89+ testProcess . StartInfo . CreateNoWindow = true ;
90+ testProcess . StartInfo . UseShellExecute = false ;
91+
92+ try
10093 {
101- throw new Exception ( "Failed to initialize rule " + GetName ( ) ) ;
94+ testProcess . Start ( ) ;
95+ PowerShellVersion = new [ ] { "core-6.1.0-windows" } ;
96+ }
97+ catch
98+ {
99+ PowerShellVersion = new [ ] { "desktop-5.1.14393.206-windows" } ;
100+ }
101+ finally
102+ {
103+ testProcess . Dispose ( ) ;
102104 }
103105 }
104106
105- foreach ( var functionDef in functionDefinitions )
107+ var psVerList = PowerShellVersion ;
108+ string settingsPath = Settings . GetShippedSettingsDirectory ( ) ;
109+
110+ foreach ( string reference in psVerList )
106111 {
107- FunctionDefinitionAst funcDef = functionDef as FunctionDefinitionAst ;
108- if ( funcDef == null )
112+ if ( settingsPath == null || ! ContainsReferenceFile ( settingsPath , reference ) )
109113 {
110- continue ;
114+ throw new ArgumentException ( nameof ( PowerShellVersion ) ) ;
111115 }
116+ }
117+
118+ ProcessDirectory ( settingsPath , psVerList ) ;
119+
120+ if ( _cmdletMap . Keys . Count != psVerList . Count ( ) )
121+ {
122+ throw new ArgumentException ( nameof ( PowerShellVersion ) ) ;
123+ }
112124
113- string functionName = funcDef . Name ;
114- foreach ( var map in cmdletMap )
125+ foreach ( FunctionDefinitionAst functionDef in functionDefinitions )
126+ {
127+ string functionName = functionDef . Name ;
128+ foreach ( KeyValuePair < string , HashSet < string > > cmdletSet in _cmdletMap )
115129 {
116- if ( map . Value . Contains ( functionName ) )
130+ if ( cmdletSet . Value . Contains ( functionName ) )
117131 {
118- diagnosticRecords . Add ( CreateDiagnosticRecord ( functionName , map . Key , functionDef . Extent ) ) ;
132+ diagnosticRecords . Add ( CreateDiagnosticRecord ( functionName , cmdletSet . Key , functionDef . Extent ) ) ;
119133 }
120134 }
121135 }
@@ -140,31 +154,6 @@ private DiagnosticRecord CreateDiagnosticRecord(string FunctionName, string PSVe
140154 }
141155
142156
143- private void Initialize ( )
144- {
145- var psVerList = PowerShellVersion ;
146-
147- string settingsPath = Settings . GetShippedSettingsDirectory ( ) ;
148-
149- foreach ( string reference in psVerList )
150- {
151- if ( settingsPath == null || ! ContainsReferenceFile ( settingsPath , reference ) )
152- {
153- return ;
154- }
155- }
156-
157- ProcessDirectory ( settingsPath , psVerList ) ;
158-
159- if ( cmdletMap . Keys . Count != psVerList . Count ( ) )
160- {
161- return ;
162- }
163-
164- initialized = true ;
165- }
166-
167-
168157 private bool ContainsReferenceFile ( string directory , string reference )
169158 {
170159 return File . Exists ( Path . Combine ( directory , reference + ".json" ) ) ;
@@ -189,7 +178,7 @@ private void ProcessDirectory(string path, IEnumerable<string> acceptablePlatfor
189178 continue ;
190179 }
191180
192- cmdletMap . Add ( fileNameWithoutExt , GetCmdletsFromData ( JObject . Parse ( File . ReadAllText ( filePath ) ) ) ) ;
181+ _cmdletMap . Add ( fileNameWithoutExt , GetCmdletsFromData ( JObject . Parse ( File . ReadAllText ( filePath ) ) ) ) ;
193182 }
194183 }
195184
0 commit comments