I'm recursively calling a function in Powershell. When I call the function using positional arguments, I get a ParameterBindingArgumentTransformationException exception, but when I call the function using named arguments that exception doesn't occur.

Below is the minimum reproducible exmple. It gets all the keys from a hashtable and outputs each sequence of keys that leads to a leaf value in a hierarchical format.

function Get-Keys([hashtable]$hash, [string]$parentKey = "") {
    $keys = @()

    foreach ($key in $hash.Keys) {
        $newKey = if ($parentKey) { "$parentKey.$key" } else { $key }
        if ($hash[$key] -is [hashtable]) {
            $output = Get-Keys($hash[$key], $newKey)
            # $output = Get-Keys -hash $hash[$key] -parentKey $newKey
            $keys += $output
        } else {
            $keys += $newKey
        }
    }

    return $keys
}

I am passing it this hashtable which has nested hashtables and lists:

$blah = @{
    "a" = @{
        "b" = "val"
        "d" = @(1,2,3)
        "e" = @{
            "f" = "foo"
        }
    }
    "h" = "bar"
}

I get the following error:

Get-Keys : Cannot process argument transformation on parameter 'hash'. Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Collections.Hashtable".
At <filename>:<linenumber> char:<charnumber>
+             $output = Get-Keys($hash[$key], $newKey)
+                               ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Get-Keys], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-Keys

However, if I switch the recursive call of the Get-Keys to the below, it suddenly starts working flawlessly and I get the expected output once the function completes its recursion:

$output = Get-Keys -hash $hash[$key] -parentKey $newKey
# outputs h a.d a.e.f a.b

My question is what the technical difference is between passing arguments as positional vs named parameters in Powershell 5.1?

One reason why this is so confusing is that in both versions of that function (with the recursive call using positional vs named arguments), the code wouldn't get to the line where $output is being assigned unless $hash[$key] was of type [hashtable]. I also used the debugger to check both parameters' expected types using the .GetType() function and $hash[$key] is of type Hashtable and $newKey is of type String.

I can't seem to find this in documentation but I do see a very similar problem here (but no explanation regarding why this happens). I see in the docs that the Set-StrictMode function "Prohibits function calls that use the syntax for calling methods". However by default, strict mode is off. Even when I try to explicitly set it to --Off` I still get the error.

0

There are 0 best solutions below