diff --git a/Engine/CommandInfoCache.cs b/Engine/CommandInfoCache.cs index ff0a6fa01..67e35c211 100644 --- a/Engine/CommandInfoCache.cs +++ b/Engine/CommandInfoCache.cs @@ -5,6 +5,7 @@ using System.Collections.Concurrent; using System.Management.Automation; using System.Linq; +using System.Management.Automation.Runspaces; namespace Microsoft.Windows.PowerShell.ScriptAnalyzer { @@ -14,16 +15,17 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer internal class CommandInfoCache { private readonly ConcurrentDictionary> _commandInfoCache; - private readonly Helper _helperInstance; + private readonly RunspacePool _runspacePool; /// /// Create a fresh command info cache instance. /// - public CommandInfoCache(Helper pssaHelperInstance) + public CommandInfoCache(Helper pssaHelperInstance, RunspacePool runspacePool) { _commandInfoCache = new ConcurrentDictionary>(); _helperInstance = pssaHelperInstance; + _runspacePool = runspacePool; } /// @@ -64,7 +66,7 @@ public CommandInfo GetCommandInfoLegacy(string commandOrAliasName, CommandTypes? /// Get a CommandInfo object of the given command name /// /// Returns null if command does not exists - private static CommandInfo GetCommandInfoInternal(string cmdName, CommandTypes? commandType) + private CommandInfo GetCommandInfoInternal(string cmdName, CommandTypes? commandType) { // 'Get-Command ?' would return % for example due to PowerShell interpreting is a single-character-wildcard search and not just the ? alias. // For more details see https://github.com/PowerShell/PowerShell/issues/9308 @@ -72,6 +74,8 @@ private static CommandInfo GetCommandInfoInternal(string cmdName, CommandTypes? using (var ps = System.Management.Automation.PowerShell.Create()) { + ps.RunspacePool = _runspacePool; + ps.AddCommand("Get-Command") .AddParameter("Name", cmdName) .AddParameter("ErrorAction", "SilentlyContinue"); diff --git a/Engine/Helper.cs b/Engine/Helper.cs index 00b9988fd..5af3a9fcf 100644 --- a/Engine/Helper.cs +++ b/Engine/Helper.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Management.Automation; using System.Management.Automation.Language; +using System.Management.Automation.Runspaces; namespace Microsoft.Windows.PowerShell.ScriptAnalyzer { @@ -29,6 +30,7 @@ public class Helper private PSVersionTable psVersionTable; private readonly Lazy _commandInfoCacheLazy; + private readonly RunspacePool _runSpacePool; #endregion @@ -113,7 +115,11 @@ internal set /// private Helper() { - _commandInfoCacheLazy = new Lazy(() => new CommandInfoCache(pssaHelperInstance: this)); + // There are 5 rules that use the CommandInfo cache but one rule (AvoidAlias) makes parallel queries. + // Therefore 10 runspaces was a heuristic measure where no more speed improvement was seen. + _runSpacePool = RunspaceFactory.CreateRunspacePool(1, 10); + _runSpacePool.Open(); + _commandInfoCacheLazy = new Lazy(() => new CommandInfoCache(pssaHelperInstance: this, runspacePool: _runSpacePool)); } /// @@ -299,11 +305,12 @@ public PSModuleInfo GetModuleManifest(string filePath, out IEnumerable psObj = null; using (var ps = System.Management.Automation.PowerShell.Create()) { + ps.RunspacePool = _runSpacePool; + ps.AddCommand("Test-ModuleManifest") + .AddParameter("Path", filePath) + .AddParameter("WarningAction", ActionPreference.SilentlyContinue); try { - ps.AddCommand("Test-ModuleManifest"); - ps.AddParameter("Path", filePath); - ps.AddParameter("WarningAction", ActionPreference.SilentlyContinue); psObj = ps.Invoke(); } catch (CmdletInvocationException e)