@@ -25,6 +25,7 @@ public class AnalysisService : IDisposable
2525 {
2626 #region Private Fields
2727
28+ private const int NumRunspaces = 2 ;
2829 private RunspacePool analysisRunspacePool ;
2930 private PSModuleInfo scriptAnalyzerModuleInfo ;
3031 private string [ ] activeRules ;
@@ -103,18 +104,16 @@ public AnalysisService(IConsoleHost consoleHost, string settingsPath = null)
103104 this . SettingsPath = settingsPath ;
104105 var sessionState = InitialSessionState . CreateDefault2 ( ) ;
105106
106- // import PSScriptAnalyzer in all runspaces
107- sessionState . ImportPSModule ( new string [ ] { "PSScriptAnalyzer" } ) ;
108-
109107 // runspacepool takes care of queuing commands for us so we do not
110108 // need to worry about executing concurrent commands
111109 this . analysisRunspacePool = RunspaceFactory . CreateRunspacePool ( sessionState ) ;
112110
113111 // having more than one runspace doesn't block code formatting if one
114112 // runspace is occupied for diagnostics
115- this . analysisRunspacePool . SetMaxRunspaces ( 2 ) ;
113+ this . analysisRunspacePool . SetMaxRunspaces ( NumRunspaces ) ;
116114 this . analysisRunspacePool . ThreadOptions = PSThreadOptions . ReuseThread ;
117115 this . analysisRunspacePool . Open ( ) ;
116+
118117 ActiveRules = IncludedRules . ToArray ( ) ;
119118 InitializePSScriptAnalyzer ( ) ;
120119 }
@@ -231,55 +230,75 @@ private async Task<ScriptFileMarker[]> GetSemanticMarkersAsync<TSettings>(
231230
232231 private void FindPSScriptAnalyzer ( )
233232 {
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 ( ) )
243234 {
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+ }
256266 }
257267 }
258268
259- private void ImportPSScriptAnalyzer ( )
269+ private async Task < bool > ImportPSScriptAnalyzerAsync ( )
260270 {
261271 if ( scriptAnalyzerModuleInfo != null )
262272 {
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+ } ) ;
270281
271282 if ( module . Count ( ) == 0 )
272283 {
273284 this . scriptAnalyzerModuleInfo = null ;
274285 Logger . Write ( LogLevel . Warning ,
275286 String . Format ( "Cannot Import PSScriptAnalyzer: {0}" ) ) ;
287+
288+ return false ;
276289 }
277290 else
278291 {
279292 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 ;
281298 }
282299 }
300+
301+ return false ;
283302 }
284303
285304 private void EnumeratePSScriptAnalyzerRules ( )
@@ -302,10 +321,15 @@ private void InitializePSScriptAnalyzer()
302321 {
303322 FindPSScriptAnalyzer ( ) ;
304323
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 ( ) ) ;
309333
310334 EnumeratePSScriptAnalyzerRules ( ) ;
311335 }
0 commit comments