Skip to content
10 changes: 7 additions & 3 deletions Engine/CommandInfoCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -14,16 +15,17 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
internal class CommandInfoCache
{
private readonly ConcurrentDictionary<CommandLookupKey, Lazy<CommandInfo>> _commandInfoCache;

private readonly Helper _helperInstance;
private readonly RunspacePool _runspacePool;

/// <summary>
/// Create a fresh command info cache instance.
/// </summary>
public CommandInfoCache(Helper pssaHelperInstance)
public CommandInfoCache(Helper pssaHelperInstance, RunspacePool runspacePool)
{
_commandInfoCache = new ConcurrentDictionary<CommandLookupKey, Lazy<CommandInfo>>();
_helperInstance = pssaHelperInstance;
_runspacePool = runspacePool;
}

/// <summary>
Expand Down Expand Up @@ -64,14 +66,16 @@ public CommandInfo GetCommandInfoLegacy(string commandOrAliasName, CommandTypes?
/// Get a CommandInfo object of the given command name
/// </summary>
/// <returns>Returns null if command does not exists</returns>
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
cmdName = WildcardPattern.Escape(cmdName);

using (var ps = System.Management.Automation.PowerShell.Create())
{
ps.RunspacePool = _runspacePool;

ps.AddCommand("Get-Command")
.AddParameter("Name", cmdName)
.AddParameter("ErrorAction", "SilentlyContinue");
Expand Down
15 changes: 11 additions & 4 deletions Engine/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -29,6 +30,7 @@ public class Helper
private PSVersionTable psVersionTable;

private readonly Lazy<CommandInfoCache> _commandInfoCacheLazy;
private readonly RunspacePool _runSpacePool;

#endregion

Expand Down Expand Up @@ -113,7 +115,11 @@ internal set
/// </summary>
private Helper()
{
_commandInfoCacheLazy = new Lazy<CommandInfoCache>(() => 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<CommandInfoCache>(() => new CommandInfoCache(pssaHelperInstance: this, runspacePool: _runSpacePool));
}

/// <summary>
Expand Down Expand Up @@ -299,11 +305,12 @@ public PSModuleInfo GetModuleManifest(string filePath, out IEnumerable<ErrorReco
Collection<PSObject> 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)
Expand Down