powershellpipelineparameter-sets

"Parameter set cannot be resolved" when piping a parameter with specific combinations of other parameters


I have written a function which uses four parameters, and four parameter sets. The first parameter, $Path, is unassigned to a set, and therefore belongs to all sets. It is also mandatory, and the only parameter that can be passed from the pipeline. However, when I do this using certain combinations of the other three parameters (all of which belong to some combination of the fours sets) when invoking the function at the end of the pipeline, I get an error indicating the set is ambiguous.

Here is my function:

function Foo-Bar {
    [CmdletBinding(DefaultParameterSetName = 'A')]

    param (
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string[]] $Path,

        [Parameter(ParameterSetName = 'A')]
        [Parameter(ParameterSetName = 'A-Secure')]
        [Switch] $OutputToConsole,

        [Parameter(Mandatory = $true,
            ParameterSetName = 'B')]
        [Parameter(Mandatory = $true,
            ParameterSetName = 'B-Secure')]
        [int] $OutputMode,

        [Parameter(Mandatory = $true,
            ParameterSetName = 'A-Secure')]
        [Parameter(Mandatory = $true,
            ParameterSetName = 'B-Secure')]
        [Switch] $Login
    )

    $PSCmdlet.ParameterSetName
}

All possible combinations of parameters are as follows:

PS C:\> Foo-Bar -Path "C:\Test.jpg"
A
PS C:\> Foo-Bar -Path "C:\Test.jpg" -OutputToConsole
A
PS C:\> Foo-Bar -Path "C:\Test.jpg" -OutputToConsole -Login
A-Secure
PS C:\> Foo-Bar -Path "C:\Test.jpg" -Login
A-Secure
PS C:\> Foo-Bar -Path "C:\Test.jpg" -OutputMode 1
B
PS C:\> Foo-Bar -Path "C:\Test.jpg" -OutputMode 1 -Login
B-Secure

Passing $Path through the pipeline alone, or with these other combinations of parameters works fine:

PS C:\> "C:\Test.jpg" | Foo-Bar
A
PS C:\> "C:\Test.jpg" | Foo-Bar -OutputToConsole
A
PS C:\> "C:\Test.jpg" | Foo-Bar -OutputToConsole -Login
A-Secure
PS C:\> "C:\Test.jpg" | Foo-Bar -OutputMode 1 -Login
B-Secure

But these two combinations result in an error:

PS C:\> "C:\Test.jpg" | Foo-Bar -Login
Foo-Bar: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.
PS C:\> "C:\Test.jpg" | Foo-Bar -OutputMode 1
Foo-Bar: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.

It seems like the biggest difference between these outcomes is $OutputToConsole, the only parameter which is optional in both of its sets. It seems as though piping a mandatory parameter causes it to become mandatory itself. On the other hand, the most confusing result involves $OutputMode, as both of its sets use distinct combinations of exclusively mandatory parameters. Set B occurs when using both $Path and $OutputMode, and that's it. So how is it that "C:\Test.jpg" | Foo-Bar -OutputMode 1 is being considered ambiguous?

I would be very grateful to anyone who can shed some light on this for me.


Solution

  • Don't ask me why.
    (The workaround below returns the same syntax for: Foo-Bar -?)
    Personally, I find parameter sets quiet confusing and verbose (therefore I did this purpose for Hierarchical Parameter Scripting #13746)

    Anyways, as a possible workaround; put the Path parameter in all the parametersets:

    function Foo-Bar {
        [CmdletBinding(DefaultParameterSetName = 'A')]
    
        param (
            [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'A')]
            [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'B')]
            [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'A-Secure')]
            [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'B-Secure')]
            [ValidateNotNullOrEmpty()]
            [string[]] $Path,
    
            [Parameter(ParameterSetName = 'A')]
            [Parameter(ParameterSetName = 'A-Secure')]
            [Switch] $OutputToConsole,
    
            [Parameter(Mandatory = $true, ParameterSetName = 'B')]
            [Parameter(Mandatory = $true, ParameterSetName = 'B-Secure')]
            [int] $OutputMode,
    
            [Parameter(Mandatory = $true, ParameterSetName = 'A-Secure')]
            [Parameter(Mandatory = $true, ParameterSetName = 'B-Secure')]
            [Switch] $Login
        )
    
        $PSCmdlet.ParameterSetName
    }
    
    "C:\Test.jpg" | Foo-Bar -Login
    A-Secure