问题
I've been getting an error running Invoke-Command
where the script block takes a parameter of type dictionary:
Cannot process argument transformation on parameter 'dictionary'. Cannot convert the "System.Collections.Hashtable" value of type "System.Collections.Hashtable" to type "System.Collections.Generic.IDictionary`2[System.String,System.String]". At line:7 char:1 + Invoke-Command -ComputerName . -ArgumentList $dictionary -ScriptBlock ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [], ParameterBindin...mationException + FullyQualifiedErrorId : ParameterArgumentTransformationError + PSComputerName : localhost
After a lot of digging I was able to reduce the script to the the MVP below to show the root of this issue:
[System.Collections.Generic.IDictionary[string, string]]$dictionary = New-Object -TypeName 'System.Collections.Generic.Dictionary[string, string]'
$dictionary.Add('one', 'hello')
$dictionary.Add('two', 'world')
Write-Verbose "Main Script $($dictionary.GetType().FullName)" -Verbose #outputs: VERBOSE: Before System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Invoke-Command -ComputerName . -ArgumentList $dictionary -ScriptBlock {
Param (
#[System.Collections.Generic.IDictionary[string, string]] #if I leave this in I get a conversion error
$dictionary
)
Write-Verbose "Function before $($dictionary.GetType().FullName)" -Verbose #outputs: VERBOSE: After System.Collections.Hashtable
function Poc {} #this line seems to cause the `$dictionary` to become a HashTable
Write-Verbose "Function after $($dictionary.GetType().FullName)" -Verbose #outputs: VERBOSE: After System.Collections.Hashtable
}
It seems that if the script block for Invoke-Command
includes any inline functions then the parameter is automatically converted to a HashTable
; whilst if the script block doesn't contain any nested function definitions the parameter is left as a System.Collections.Generic.IDictionary[string, string]
.
Am I misusing this feature / is there a common workaround? Or is this a just a bug in PowerShell?
回答1:
This is a known problem with the deserialization code that is involved in PowerShell remoting (which is what Invoke-Command -ComputerName
is based on), unfortunately, as of PowerShell Core 7.0.0-preview.2:
On deserialization, any object that implements the IDictionary
interface is incorrectly assumed to always be a regular, non-generic [hashtable]
[1] and deserialized as such.
This is especially problematic when the original object was an ordered dictionary[2], because the ordering of the keys is lost, as is the ability to index into them.
See this GitHub issue, which is tagged as "up for grabs", meaning that the community is free to offer a PR that fixes the problem.
[1] System.Collections.Hashtable, creatable in PowerShell with @{ ... }
literals, where both the keys and values are [object]
-typed.
[2] E.g., System.Collections.Specialized.OrderedDictionary, creatable in PowerShell with [ordered] @{ ... }
literals, also with [object]
-typed keys and values (non-generic); suprisingly, as of this writing, there is no generic ordered dictionary type - see this question.
来源:https://stackoverflow.com/questions/57572937/property-passed-to-invoke-command-changes-type-from-idictionary-to-hashtable