Why doesn't this work: $PSBoundParameters.CopyTo($boundParameters, 0)

This topic contains 2 replies, has 3 voices, and was last updated by  Ben Lemmond 4 years, 6 months ago.

  • Author
  • #11110


    I'm trying to create a copy of $PSBoundParameters. I've got this:

    $boundParameters = [System.Collections.Generic.KeyValuePair[string,object][]]@()
    $PSBoundParameters.CopyTo($boundParameters, 0)

    but it produces this:

    Cannot find an overload for "CopyTo" and the argument count: "2".
    At C:\Users\Me\PowerShell\TEST.ps1:43 char:9
    + $PSBoundParameters.CopyTo($boundParameters, 0)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest

    The attached screenshot, from ISE, suggests it should work. Is it me? Is a PowerShell funny?

  • #11114

    Dave Wyatt

    What is it that you want to accomplish with this code? You can simply do $boundParameters = $PSBoundParameters, but both variables will refer to the same Dictionary (technically, [System.Management.Automation.PSBoundParametersDictionary). Adding or removing keys / values from one dictionary would affect the other.

    Assuming you got the CopyTo function working, you'd have one object ($PSBoundParameters) that's still a dictionary, and one that's just an array of key/value pairs, but they'd still refer to the same Value objects. Changes made from one place or the other might affect both, depending on the types of objects stored in the dictionary.

    In any case, the reason you're having trouble is because that method is an explicit interface implementation, and working with those is a bit of a pain in PowerShell. I tried to get it working this morning, but haven't quite got there yet for some reason; here's my current test code:

    function Test
        param (
            $FirstArg, $SecondArg, $ThirdArg
        $boundParameters = New-Object -TypeName 'System.Collections.Generic.KeyValuePair`2[System.String,System.Object][]' -ArgumentList $PSBoundParameters.Count
        $type = [System.Collections.Generic.ICollection[System.Collections.Generic.KeyValuePair[String,Object]]]
        $method = $type.GetMethod('CopyTo')
        $arguments = [Object[]]($boundParameters, 0)
        $method.Invoke($PSBoundParameters, $arguments)
    Test 1 2 3

    You can find some more information on this topic at http://www.vistax64.com/powershell/169391-access-interfaces-members-net-object.html. Right now, I'm getting the error 'Exception calling "Invoke" with "2" argument(s): "Object of type 'System.Management.Automation.PSObject' cannot be converted to type 'System.Collections.Generic.KeyValuePair`2[System.String,System.Object][]'."' I'm not sure why, as I'm outputting the type of $boundParameters earlier in the function, and it's not a PSObject.

    As a workaround, you could just create the copy yourself, ie:

    function Test
    param (
    $FirstArg, $SecondArg, $ThirdArg

    $boundParameters = New-Object -TypeName 'System.Collections.Generic.KeyValuePair`2[System.String,System.Object][]' -ArgumentList $PSBoundParameters.Count

    $i = 0
    foreach ($pair in $PSBoundParameters.GetEnumerator())
    $boundParameters[$i++] = $pair


    Test 1 2 3

  • #12097

    Ben Lemmond

    I don't think CopyTo() will get you what you want. That will result in an array of KeyValuePair objects, i.e. not a lookup dictionary.
    If that is indeed what you want, Dave is correct about why it does not work. The Dictionary class implements the CopyTo method explicitly which basically makes it a private method. Therefore, it just needs to be cast to an ICollection. Also, the destination array needs to be allocated first.

    # Init destination array
    $boundParameters = @($null) * $PSBoundParameters.Count;
    # Cast to ICollection before calling CopyTo()
    ([System.Collections.ICollection]$PSBoundParameters).CopyTo($boundParameters, 0);

    However, I think this is probably what you want:
    $boundParameters = @{} + $PSBoundParameters;

    This will get you a copy of $PSBoundParameters with which you can add/remove items without affecting $PSBoundParameters.

You must be logged in to reply to this topic.