Skip to content

Allow explicitly specified named parameter to supersede the one from hashtable splatting #13114

Closed
@daxian-dbw

Description

@daxian-dbw

Problem Statement

Today, the splatting of a Hashtable in a PowerShell command invocation works just like explicitly specifying those key-value pairs as individual named parameters in the command line, so the following example doesn't work:

$common = @{
    AddressPrefix = "10.0.0.0/16"
    ResourceGroupName = "MyResourceGroup"
    Location = "westus"
}

New-AzVirtualNetwork @common -Name MyNet -AddressPrefix "10.0.0.0/24"

> New-AzVirtualNetwork: Cannot bind parameter because parameter 'AddressPrefix' is specified more than once. To provide 
> multiple values to parameters that can accept multiple values, use the array syntax. For example, "-parameter 
> value1,value2,value3".

$common may work well for all other 99 New-AzVirtualNetwork calls in my scripts, but there is one instance where a different address prefix is required. In such a case, I would have to temporarily change the Hashtable and restore it after the invocation, like this:

try {
    $commonAddrPrefix = $common.AddressPrefix
    $common.AddressPrefix = "10.0.0.0/24"

    New-AzVirtualNetwork @common -Name MyNet
}
finally {
    $common.AddressPrefix = $commonAddrPrefix
}

Proposed technical implementation details

The proposal is to allow an explicitly specified named parameter to supersede the same one that is expanded from splatting a Hashtable.

  1. To be clear, I want to point out that the proposal targets "Hashtable splatting" and "explicitly specified named parameters" only.
    (a). Array splatting won't change its current behavior.
    (b). Hashtable splatting won't change its current behavior when working with explicitly specified positional parameters.
    (c). Both Array splatting and Hashtable splatting keep their current behaviors when working with native command.

  2. The CommandParameterInternal created from splatting a Hashtable needs to be marked as came-from-splatting.

  3. To determine whether 2 named parameters are the same, parameters need to be resolved to cover the use of parameter alias or prefix (e.g. -s for -Seconds in Start-Sleep), so the work should be done in the parameter binder.

  4. Script-block-to-PowerShell conversion also does splatting. It calls powershell.AddParameter(string paramName, object paramValue) for each of the key-value pair of the Hashtable. The "came-from-splatting" message needs to be passed on to the PowerShell instance, so we will need to add a boolean property CamFromSplatting to CommandParameter to track that information, which will be used when invoking the PowerShell instance.

  5. Challenge: the script-block-to-PowerShell conversion is also used in remoting scenario when the script block to invoke on the remote side contains command invocations only, for example Invoke-Command { param($hash) dir @hash } -ArgumentList @{ path = "c:\" }. In that case, the generated PowerShell instance will be used to create a remote pipeline and run on the remote side, so the new member added to CommandParameter will likely cause serialization/deserialization problems. More investigation is needed.

Update to (5): powershell committee agreed (#13108 (comment)) to not use GetPowerShell in remote command execution, so (5) won't be a blocker.

/cc @SteveL-MSFT @JamesWTruher @joeyaiello

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugWG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions