Skip to content

Commit 7651087

Browse files
committed
Fix PSScriptAnalyzer module loading in new async AnalysisService
This change fixes the way that the PSScriptAnalyzer module gets loaded in the new asynchronous AnalysisService. Since we changed to using the InitialSessionState to load the module, we were unable to specify the exact version of the module we needed. This change goes back to an explicit Import-Module across the runspaces in the RunspacePool.
1 parent 2c7709b commit 7651087

File tree

1 file changed

+62
-38
lines changed

1 file changed

+62
-38
lines changed

src/PowerShellEditorServices/Analysis/AnalysisService.cs

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)