powershellmutual-exclusionpowershell-cmdlet

Sets of mutually exclusive parameters in PowerShell: Why is this ambiguous?


I've been trying to get multiple sets of mutual exclusions to work. I want "Width" mutually exclusive to "WidthReset" and "Height" to be mutually exclusive with "HeightReset".

Help for the cmdlet shows:

    Get-ArgTest [-Width <int>] [-Height <int>]  [<CommonParameters>]
    Get-ArgTest [-Width <int>] [-HeightReset]  [<CommonParameters>]
    Get-ArgTest [-Height <int>] [-WidthReset]  [<CommonParameters>]
    Get-ArgTest [-WidthReset] [-HeightReset]  [<CommonParameters>]

See the following code.

Everything works, but Get-ArgTest -WidthReset seems to be ambiguous.

Why is this one case is ambiguous? Other, symmetrical cases are not flagged as ambiguous.

How can I resolve the ambiguity?

Changing the DefaultParameterSetName to B or C changes which case is ambiguous.

That indicates to me that it should work.

##########################################
# This cmdlet *should* accept
# [-Width | -WidthReset] [-Height | -HeightReset]
##########################################
function Get-ArgTest
{
  [CmdletBinding(DefaultParameterSetName = 'A')]
    param(
            [Parameter(ParameterSetName='A')]
            [Parameter(ParameterSetName='B')]
            [int] $Width,

            [Parameter(ParameterSetName='C')]
            [Parameter(ParameterSetName='A')]
            [int] $Height,

            [Parameter(ParameterSetName='C')]
            [Parameter(ParameterSetName='D')]
            [switch] $WidthReset,

            [Parameter(ParameterSetName='B')]
            [Parameter(ParameterSetName='D')]
            [switch] $HeightReset
    )

    Write-Output "HELLO, Width=$Width, Height=$Height, WidthReset=$WidthReset, HeightReset=$HeightReset"
}

##########################################
# Tests
##########################################
# First, display HELP
Get-ArgTest -?

####
## Try each combination
# First, just the values
Get-ArgTest 
Get-ArgTest -Width 2
Get-ArgTest          -Height 4
Get-ArgTest -Width 2 -Height 4

# Values and the opposite reset
Get-ArgTest -Width 2                         -HeightReset
Get-ArgTest          -Height 4   -WidthReset

# The Resets
Get-ArgTest                      -WidthReset -HeightReset
Get-ArgTest                      -WidthReset -HeightReset:$False
Get-ArgTest                      -WidthReset:$False -HeightReset:$True

# I cannot get the following cases to work :-(
Get-ArgTest                      -WidthReset
Get-ArgTest                                  -HeightReset


Solution

  • To avoid the ambiguity, make -WidthReset and -HeightReset mandatory in your D parameter set:

    function Get-ArgTest
    {
      [CmdletBinding(DefaultParameterSetName = 'A')]
        param(
                [Parameter(ParameterSetName='A')]
                [Parameter(ParameterSetName='B')]
                [int] $Width,
    
                [Parameter(ParameterSetName='C')]
                [Parameter(ParameterSetName='A')]
                [int] $Height,
    
                [Parameter(ParameterSetName='C')]
                [Parameter(ParameterSetName='D', Mandatory)]
                [switch] $WidthReset,
    
                [Parameter(ParameterSetName='B')]
                [Parameter(ParameterSetName='D', Mandatory)]
                [switch] $HeightReset
        )
    
        Write-Output "HELLO, Width=$Width, Height=$Height, WidthReset=$WidthReset, HeightReset=$HeightReset"
    }
    

    This results in the following syntax diagram (Get-Command -Syntax Get-ArgTest):

    Get-ArgTest [-Width <int>] [-Height <int>] [<CommonParameters>]
    
    Get-ArgTest [-Width <int>] [-HeightReset] [<CommonParameters>]
    
    Get-ArgTest [-Height <int>] [-WidthReset] [<CommonParameters>]
    
    Get-ArgTest -WidthReset -HeightReset [<CommonParameters>]
    

    As a result:


    As for what you tried:

    With your original function definition, the following calls are ambiguous:

    Get-ArgTest                      -WidthReset
    Get-ArgTest                                  -HeightReset
    

    because the former matches both parameter set C and D,
    and the latter both B and D,
    and none of them is the default parameter set (which would act as the tie-breaker).