Powershell parameter set resolution with explicit parameter fails

powershell

Let's say I have this function :

function Foo{
    [CmdLetBinding()]
    param(
        [Parameter(Mandatory=$true,ParameterSetName="A",Position=0)] 
        [Parameter(Mandatory=$true,ParameterSetName="both",Position=0)] 
        [int]
        $A,

        [Parameter(Mandatory=$true,ParameterSetName="B",Position=0)] 
        [Parameter(Mandatory=$true,ParameterSetName="both",Position=1)] 
        [int]
        $B
    )

    Write-Host $PsCmdlet.ParameterSetName

}

I expect this method to expect either A, or B or both. Never none.

However, if I call this :

Foo -A 1 -B 2 # outputs "both" as expected
Foo -B 3 # error
Foo -A 4 # error

The error I get is :

Foo : Parameter set cannot be resolved using the specified named parameters.
At c:\pathto:75 char:4
+ Foo <<<<  -B 3
    + CategoryInfo          : InvalidArgument: (:) [Foo], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Foo

Foo : Parameter set cannot be resolved using the specified named parameters.
At c:\pathto.ps1:76 char:4
+ Foo <<<<  -A 4
    + CategoryInfo          : InvalidArgument: (:) [Foo], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Foo

I troubled, because as you can see, I explicitly specify the parameters' name.

How should I write my function to works as expected?

Best Answer

You probably want to implement parameter checking in your function then. MS says that Parameter sets have to have one parameter that is unique to its parameter set. So, each parameter set must have one parameter that does not belong to any other parameter set, which is the reason for your error when trying to call the function w/ only one parameter, it doesn't know which parameter set to assign b/c the parameter supplied is not unique to a particular parameter set. I came close with

 function Foof{
[CmdLetBinding(DefaultParameterSetName="None")]
param(

    [Parameter(Mandatory=$false,ParameterSetName="A")]
    [Parameter(Position=0)]
    [int]
    $A,

    [Parameter(Mandatory=$false,ParameterSetName="B")]
    [Parameter(Mandatory=$false,ParameterSetName="both")]  
    [Parameter(Position=1)]
    [int]
    $B,

    [Parameter(Mandatory=$false,ParameterSetName="both")]  
    [int]
    $C=$true

)

Write-Host $PsCmdlet.ParameterSetName
write-host "A=$A and B=$B and C=$C"

}

I thought that assigning $C a default value would give your expected behavior, but it doesn't b/c the parameter has to be explicitly declared when calling the function.

You'll notice I set the DefaultParameterSetName to "None". What this does is give you a fast was to check for the case if neither parameters were submitted.

You could do something like check if $PsCmdlet.ParameterSetName -eq "None" then Read-Host whatever variable you want supplied, or just output an error that says either variable a or b should be supplied.

http://technet.microsoft.com/en-us/library/hh847743.aspx

Related Question