diff --git a/Engine/CommandInfoCache.cs b/Engine/CommandInfoCache.cs
index 02e926b53..dbcb41eda 100644
--- a/Engine/CommandInfoCache.cs
+++ b/Engine/CommandInfoCache.cs
@@ -57,8 +57,9 @@ protected virtual void Dispose(bool disposing)
///
/// Name of the command to get a commandinfo object for.
/// What types of command are needed. If omitted, all types are retrieved.
+ /// When needed due to runspace affinity problems of some PowerShell objects.
///
- public CommandInfo GetCommandInfo(string commandName, CommandTypes? commandTypes = null)
+ public CommandInfo GetCommandInfo(string commandName, CommandTypes? commandTypes = null, bool bypassCache = false)
{
if (string.IsNullOrWhiteSpace(commandName))
{
@@ -66,6 +67,10 @@ public CommandInfo GetCommandInfo(string commandName, CommandTypes? commandTypes
}
var key = new CommandLookupKey(commandName, commandTypes);
+ if (bypassCache)
+ {
+ return GetCommandInfoInternal(commandName, commandTypes);
+ }
// Atomically either use PowerShell to query a command info object, or fetch it from the cache
return _commandInfoCache.GetOrAdd(key, new Lazy(() => GetCommandInfoInternal(commandName, commandTypes))).Value;
}
diff --git a/Engine/Helper.cs b/Engine/Helper.cs
index cbd8d0cd3..743cb4d68 100644
--- a/Engine/Helper.cs
+++ b/Engine/Helper.cs
@@ -673,10 +673,11 @@ public bool PositionalParameterUsed(CommandAst cmdAst, bool moreThanTwoPositiona
///
///
///
+ ///
///
- public CommandInfo GetCommandInfo(string name, CommandTypes? commandType = null)
+ public CommandInfo GetCommandInfo(string name, CommandTypes? commandType = null, bool bypassCache = false)
{
- return CommandInfoCache.GetCommandInfo(name, commandTypes: commandType);
+ return CommandInfoCache.GetCommandInfo(name, commandTypes: commandType, bypassCache: bypassCache);
}
///
diff --git a/Rules/UseCorrectCasing.cs b/Rules/UseCorrectCasing.cs
index d1f579731..9569b1904 100644
--- a/Rules/UseCorrectCasing.cs
+++ b/Rules/UseCorrectCasing.cs
@@ -69,7 +69,19 @@ public override IEnumerable AnalyzeScript(Ast ast, string file
var commandParameterAsts = commandAst.FindAll(
testAst => testAst is CommandParameterAst, true).Cast();
- var availableParameters = commandInfo.Parameters;
+ Dictionary availableParameters;
+ try
+ {
+ availableParameters = commandInfo.Parameters;
+ }
+ // It's a known issue that objects from PowerShell can have a runspace affinity,
+ // therefore if that happens, we query a fresh object instead of using the cache.
+ // https://github.com/PowerShell/PowerShell/issues/4003
+ catch (InvalidOperationException)
+ {
+ commandInfo = Helper.Instance.GetCommandInfo(commandName, bypassCache: true);
+ availableParameters = commandInfo.Parameters;
+ }
foreach (var commandParameterAst in commandParameterAsts)
{
var parameterName = commandParameterAst.ParameterName;
diff --git a/Tests/Rules/UseCorrectCasing.tests.ps1 b/Tests/Rules/UseCorrectCasing.tests.ps1
index 7343677ff..a5280a6e3 100644
--- a/Tests/Rules/UseCorrectCasing.tests.ps1
+++ b/Tests/Rules/UseCorrectCasing.tests.ps1
@@ -73,4 +73,13 @@ Describe "UseCorrectCasing" {
Invoke-Formatter 'Get-Process -NonExistingParameterName' -ErrorAction Stop
}
+ It "Does not throw when correcting certain cmdlets (issue 1516)" {
+ $scriptDefinition = 'Get-Content;Test-Path;Get-ChildItem;Get-Content;Test-Path;Get-ChildItem'
+ $settings = @{ 'Rules' = @{ 'PSUseCorrectCasing' = @{ 'Enable' = $true } } }
+ {
+ 1..100 |
+ ForEach-Object { $null = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings -ErrorAction Stop }
+ } |
+ Should -Not -Throw
+ }
}