Reputation: 23673
Up till now I was more or less avoiding parameter-sets in my PowerShell script as I find them very verbose and quiet difficult to implement for complex dependencies.
There are several similar questions and answers at StackOverflow but I can find an acceptable solution or workaround to my situation. The actual script is even more complex but this is were I get stuck:
Function Test-ParamSet {
[CmdletBinding(DefaultParameterSetName='Param1')][OutputType([Object[]])]Param (
[Parameter(ParameterSetName = 'Param1', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param1Switch', Mandatory = $True)]
$Param1,
[Parameter(ParameterSetName = 'Param2', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param2Switch', Mandatory = $True)]
$Param2,
[Parameter(ParameterSetName = 'Param3', Mandatory = $True)]
$Param3,
[Parameter(ParameterSetName = 'Param1Switch')]
[Parameter(ParameterSetName = 'Param2Switch')]
[Switch]$Switch1,
[Parameter(ParameterSetName = 'Param1Switch')]
[Parameter(ParameterSetName = 'Param2Switch')]
[Switch]$Switch2
)
Write-Host $PsCmdlet.ParameterSetName
}
Parameter rules:
Param#
(Param1
, Param2
or Param3
) parameter should be suppliedParam#
(Param1
, Param2
or Param3
) parameter can be suppliedSwitch1
and Switch2
) are optional can only be supplied (either one or both) with the Param1
or Param2
parameterMeaning the following commands should produce an error:
Test-ParamSet
Test-ParamSet -Param3 'Test' -Switch1
And the following commands should be accepted:
Test-ParamSet -Param1 'Test'
Test-ParamSet -Param1 'Test' -Switch1
Test-ParamSet -Param2 'Test' -Switch1 -Switch2
The problem is with the following command:
Test-ParamSet -Param2 'Test'
It generates an unexpected error:
Test-ParamSet : 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. At line:1 char:1 + Test-ParamSet -Param2 'Test' + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Test-ParamSet], ParameterBindingException + FullyQualifiedErrorId : AmbiguousParameterSet,Test-ParamSet
I guess this is related to this github issue mentioned by @mklement0 in How do you change a parameter's throw message?.
But how can I adequately resolve or workaround this using parameter-sets?
Upvotes: 0
Views: 595
Reputation: 13463
To add to @SagePourpre and @iRon comment and add what may be relevant extra information.
In this instance, the error is correct, and the issue is that you are matching 2 parameter sets at the same time --> with no default parameter set specified.
e.g. First parameter set test:
Test-ParamSet -Param1 'Test'
These match both Parameter sets Param1
and Param1Switch
. It matches the other parameter set because the other two switches are optional. But, since you specify the DefaultParameterSetName='Param1'
then Param1
wins by default.
In the second parameter set test:
Test-ParamSet -Param2 'Test'
Again, these match both Parameter sets Param2
and Param2Switch
. But since there is no Default Parameter Set specified to "win" the disagreement, and the switches are optional (to match the second parameter set), it throws the error.
The solution is to simplify the set names so that it only can match one set at a time. Especially when you deal with optional parameters:
Function Test-ParamSet {
[CmdletBinding(DefaultParameterSetName='Param1')][OutputType([Object[]])]Param (
[Parameter(ParameterSetName = 'Param1', Mandatory = $True)]
$Param1,
[Parameter(ParameterSetName = 'Param2', Mandatory = $True)]
$Param2,
[Parameter(ParameterSetName = 'Param3', Mandatory = $True)]
$Param3,
[Parameter(ParameterSetName = 'Param1')]
[Parameter(ParameterSetName = 'Param2')]
[Switch]$Switch1,
[Parameter(ParameterSetName = 'Param1')]
[Parameter(ParameterSetName = 'Param2')]
[Switch]$Switch2
)
Write-Host $PsCmdlet.ParameterSetName
}
The Other way of doing it is to specify the switches as mandatory to force the parameter set name to a specific one. e.g:
Function Test-ParamSet {
[CmdletBinding(DefaultParameterSetName='Param1')][OutputType([Object[]])]Param (
[Parameter(ParameterSetName = 'Param1', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param1Switch', Mandatory = $True)]
$Param1,
[Parameter(ParameterSetName = 'Param2', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param2Switch', Mandatory = $True)]
$Param2,
[Parameter(ParameterSetName = 'Param3', Mandatory = $True)]
$Param3,
[Parameter(ParameterSetName = 'Param1Switch', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param2Switch', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param1And2Switch', Mandatory = $True)]
[Switch]$Switch1,
[Parameter(ParameterSetName = 'Param1Switch', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param2Switch', Mandatory = $True)]
[Parameter(ParameterSetName = 'Param1And2Switch', Mandatory = $True)]
[Switch]$Switch2
)
Write-Host $PsCmdlet.ParameterSetName
}
This way you only have one ParameterSet option for all possible solutions, and can handle special cases with switches.
Upvotes: 1
Reputation: 10333
The switch parameters should be member of the Param1 and Param2 naming set.
Then, the Param1Switch & Param2Switch naming set can be removed from $Param1
& $Param2
definition.
Here's the end result.
Function Test-ParamSet {
[CmdletBinding(DefaultParameterSetName='Param1')][OutputType([Object[]])]Param (
[Parameter(ParameterSetName = 'Param1', Mandatory = $True)]
$Param1,
[Parameter(ParameterSetName = 'Param2', Mandatory = $True)]
$Param2,
[Parameter(ParameterSetName = 'Param3', Mandatory = $True)]
$Param3,
[Parameter(ParameterSetName = 'Param1')]
[Parameter(ParameterSetName = 'Param2')]
[Switch]$Switch1,
[Parameter(ParameterSetName = 'Param1')]
[Parameter(ParameterSetName = 'Param2')]
[Switch]$Switch2
)
Write-Host $PsCmdlet.ParameterSetName
}
Upvotes: 1