@@ -25,6 +25,7 @@ public class AnalysisService : IDisposable
25
25
{
26
26
#region Private Fields
27
27
28
+ private const int NumRunspaces = 2 ;
28
29
private RunspacePool analysisRunspacePool ;
29
30
private PSModuleInfo scriptAnalyzerModuleInfo ;
30
31
private string [ ] activeRules ;
@@ -103,18 +104,16 @@ public AnalysisService(IConsoleHost consoleHost, string settingsPath = null)
103
104
this . SettingsPath = settingsPath ;
104
105
var sessionState = InitialSessionState . CreateDefault2 ( ) ;
105
106
106
- // import PSScriptAnalyzer in all runspaces
107
- sessionState . ImportPSModule ( new string [ ] { "PSScriptAnalyzer" } ) ;
108
-
109
107
// runspacepool takes care of queuing commands for us so we do not
110
108
// need to worry about executing concurrent commands
111
109
this . analysisRunspacePool = RunspaceFactory . CreateRunspacePool ( sessionState ) ;
112
110
113
111
// having more than one runspace doesn't block code formatting if one
114
112
// runspace is occupied for diagnostics
115
- this . analysisRunspacePool . SetMaxRunspaces ( 2 ) ;
113
+ this . analysisRunspacePool . SetMaxRunspaces ( NumRunspaces ) ;
116
114
this . analysisRunspacePool . ThreadOptions = PSThreadOptions . ReuseThread ;
117
115
this . analysisRunspacePool . Open ( ) ;
116
+
118
117
ActiveRules = IncludedRules . ToArray ( ) ;
119
118
InitializePSScriptAnalyzer ( ) ;
120
119
}
@@ -231,55 +230,75 @@ private async Task<ScriptFileMarker[]> GetSemanticMarkersAsync<TSettings>(
231
230
232
231
private void FindPSScriptAnalyzer ( )
233
232
{
234
- var modules = InvokePowerShell (
235
- "Get-Module" ,
236
- new Dictionary < string , object >
237
- {
238
- { "ListAvailable" , true } ,
239
- { "Name" , "PSScriptAnalyzer" }
240
- } ) ;
241
- var psModule = modules . Count ( ) == 0 ? null : modules . FirstOrDefault ( ) ;
242
- if ( psModule != null )
233
+ using ( var ps = System . Management . Automation . PowerShell . Create ( ) )
243
234
{
244
- scriptAnalyzerModuleInfo = psModule . ImmediateBaseObject as PSModuleInfo ;
245
- Logger . Write (
246
- LogLevel . Normal ,
247
- string . Format (
248
- "PSScriptAnalyzer found at {0}" ,
249
- scriptAnalyzerModuleInfo . Path ) ) ;
250
- }
251
- else
252
- {
253
- Logger . Write (
254
- LogLevel . Normal ,
255
- "PSScriptAnalyzer module was not found." ) ;
235
+ ps . RunspacePool = this . analysisRunspacePool ;
236
+
237
+ ps . AddCommand ( "Get-Module" )
238
+ . AddParameter ( "ListAvailable" )
239
+ . AddParameter ( "Name" , "PSScriptAnalyzer" ) ;
240
+
241
+ ps . AddCommand ( "Sort-Object" )
242
+ . AddParameter ( "Descending" )
243
+ . AddParameter ( "Property" , "Version" ) ;
244
+
245
+ ps . AddCommand ( "Select-Object" )
246
+ . AddParameter ( "First" , 1 ) ;
247
+
248
+ var modules = ps . Invoke ( ) ;
249
+
250
+ var psModule = modules == null ? null : modules . FirstOrDefault ( ) ;
251
+ if ( psModule != null )
252
+ {
253
+ scriptAnalyzerModuleInfo = psModule . ImmediateBaseObject as PSModuleInfo ;
254
+ Logger . Write (
255
+ LogLevel . Normal ,
256
+ string . Format (
257
+ "PSScriptAnalyzer found at {0}" ,
258
+ scriptAnalyzerModuleInfo . Path ) ) ;
259
+ }
260
+ else
261
+ {
262
+ Logger . Write (
263
+ LogLevel . Normal ,
264
+ "PSScriptAnalyzer module was not found." ) ;
265
+ }
256
266
}
257
267
}
258
268
259
- private void ImportPSScriptAnalyzer ( )
269
+ private async Task < bool > ImportPSScriptAnalyzerAsync ( )
260
270
{
261
271
if ( scriptAnalyzerModuleInfo != null )
262
272
{
263
- var module = InvokePowerShell (
264
- "Import-Module" ,
265
- new Dictionary < string , object >
266
- {
267
- { "ModuleInfo" , scriptAnalyzerModuleInfo } ,
268
- { "PassThru" , true } ,
269
- } ) ;
273
+ var module =
274
+ await InvokePowerShellAsync (
275
+ "Import-Module" ,
276
+ new Dictionary < string , object >
277
+ {
278
+ { "ModuleInfo" , scriptAnalyzerModuleInfo } ,
279
+ { "PassThru" , true } ,
280
+ } ) ;
270
281
271
282
if ( module . Count ( ) == 0 )
272
283
{
273
284
this . scriptAnalyzerModuleInfo = null ;
274
285
Logger . Write ( LogLevel . Warning ,
275
286
String . Format ( "Cannot Import PSScriptAnalyzer: {0}" ) ) ;
287
+
288
+ return false ;
276
289
}
277
290
else
278
291
{
279
292
Logger . Write ( LogLevel . Normal ,
280
- String . Format ( "Successfully imported PSScriptAnalyzer" ) ) ;
293
+ String . Format (
294
+ "Successfully imported PSScriptAnalyzer {0}" ,
295
+ scriptAnalyzerModuleInfo . Version ) ) ;
296
+
297
+ return true ;
281
298
}
282
299
}
300
+
301
+ return false ;
283
302
}
284
303
285
304
private void EnumeratePSScriptAnalyzerRules ( )
@@ -302,10 +321,15 @@ private void InitializePSScriptAnalyzer()
302
321
{
303
322
FindPSScriptAnalyzer ( ) ;
304
323
305
- // this import is redundant if we are importing the
306
- // module while creating the runspace, but it helps
307
- // us log the import related messages.
308
- ImportPSScriptAnalyzer ( ) ;
324
+ List < Task > importTasks = new List < Task > ( ) ;
325
+ for ( int i = 0 ; i < NumRunspaces ; i ++ )
326
+ {
327
+ importTasks . Add (
328
+ ImportPSScriptAnalyzerAsync ( ) ) ;
329
+ }
330
+
331
+ // Wait for the import requests to complete or fail
332
+ Task . WaitAll ( importTasks . ToArray ( ) ) ;
309
333
310
334
EnumeratePSScriptAnalyzerRules ( ) ;
311
335
}
0 commit comments