5

Is there a way to have PowerShell enforce mutually exclusive parameters if there is more than one group (of mutually exclusive parameters)?

For example, consider these parameters in script Test.ps1 (all are optional and non-positional):

Param(
    # GROUP A (a1 and a2 are mutually exclusive)
    [switch]$a1,
    [switch]$a2,

    # GROUP B (b1 and b2 are mutually exclusive)
    [switch]$b1,
    [switch]$b2
)

Is there a way to enforce that at most one parameter from group A (i.e. $a1 or $a2) and/or at most one parameter from group B (i.e. $b1 or $b2) are specified?

The following calls would be valid:

.\Test.ps1
.\Test.ps1 -a1
.\Test.ps1 -a2
.\Test.ps1 -b1
.\Test.ps1 -b2
.\Test.ps1 -a1 -b1
.\Test.ps1 -a1 -b2
.\Test.ps1 -a2 -b1
.\Test.ps1 -a2 -b2

The following calls would be invalid:

.\Test.ps1 -a1 -a2 -b1 -b2
.\Test.ps1 -a1 -b1 -b2
.\Test.ps1 -a2 -b1 -b2
.\Test.ps1 -a1 -a2 -b1
.\Test.ps1 -a1 -a2 -b2

I know how to use ParameterSetName to enforce a single group of mutually exclusive parameters, but I cannot figure out how to enforce multiple groups. Not even sure if it is possible at all. Notice that the real example is more complex than the sample above (each group has more than one parameter and they are not all switches).

UPDATE: From the recommendation in a comment, I added parameter sets:

Param(
    # GROUP A (a1 and a2 are mutually exclusive)
    [Parameter(ParameterSetName="a1")]
    [Parameter(ParameterSetName="b1")]
    [Parameter(ParameterSetName="b2")]
    [switch]$a1,

    [Parameter(ParameterSetName="a2")]
    [Parameter(ParameterSetName="b1")]
    [Parameter(ParameterSetName="b2")]
    [switch]$a2,

    # GROUP B (b1 and b2 are mutually exclusive)
    [Parameter(ParameterSetName="a1")]
    [Parameter(ParameterSetName="a2")]
    [Parameter(ParameterSetName="b1")]
    [switch]$b1,

    [Parameter(ParameterSetName="a1")]
    [Parameter(ParameterSetName="a2")]
    [Parameter(ParameterSetName="b2")]
    [switch]$b2
)

This does not seem to do what I need it to do:

PS D:\Scripts> Get-Help .\Test.ps1
Test.ps1 [-a1] [-a2] [-b2] [<CommonParameters>]
Test.ps1 [-a1] [-a2] [-b1] [<CommonParameters>]
Test.ps1 [-a1] [-b1] [-b2] [<CommonParameters>]
Test.ps1 [-a2] [-b1] [-b2] [<CommonParameters>]
6
  • What is wrong with creating multiple parameter sets? Yes, it could potentially be a lot of sets, but it is probably the best way to do it. Commented Mar 13, 2019 at 19:27
  • I'd like to see an example because I cannot make it work with multiple sets. Maybe I am not doing it right, but in this example each parameter would have its own set and sets that are not members of the groups, like $a1: a1,b1,b2, $a2:a2,b1,b2, $b1:b1,a1,a1, and $b2:b2,a1,a2, right? If so, it does not work. Commented Mar 13, 2019 at 19:52
  • Do you see what I mean? Or am I not doing it right? Commented Mar 13, 2019 at 19:59
  • I'll update the original post with the example. Commented Mar 13, 2019 at 20:00
  • 1
    Revisiting your requirements I think this cannot be done with parameter sets. While the requirement to invoke the script without parameters could be implemented by adding another (empty) parameter set and making it the default, the requirement to run the script with any combination of the parameters makes the parameter set approach unworkable, b/c parameter sets become indistinguishable from each other. You need to use dynamic parameters here. Commented Mar 13, 2019 at 22:53

1 Answer 1

7

You can resolve "ParameterSet" by setting "Mandatory"

function paramtest
{
    <# .Synopsis #>
    [CmdletBinding(DefaultParameterSetName = "default")]
    Param(
        # GROUP A (a1 and a2 are mutually exclusive)
        [Parameter(ParameterSetName="a1")]
        [Parameter(Mandatory, ParameterSetName="a1b1")]
        [Parameter(Mandatory, ParameterSetName="a1b2")]
        [switch]$a1,

        [Parameter(ParameterSetName="a2")]
        [Parameter(Mandatory, ParameterSetName="a2b1")]
        [Parameter(Mandatory, ParameterSetName="a2b2")]
        [switch]$a2,

        # GROUP B (b1 and b2 are mutually exclusive)
        [Parameter(ParameterSetName="b1")]
        [Parameter(Mandatory, ParameterSetName="a1b1")]
        [Parameter(Mandatory, ParameterSetName="a2b1")]
        [switch]$b1,

        [Parameter(ParameterSetName="b2")]
        [Parameter(Mandatory, ParameterSetName="a1b2")]
        [Parameter(Mandatory, ParameterSetName="a2b2")]
        [switch]$b2
    )

    "ParameterSetName is {0}" -f $PSCmdlet.ParameterSetName
}

The result of Get-Help is below.

PS > help paramtest | foreach syntax

paramtest [<CommonParameters>]

paramtest -a1 -b2 [<CommonParameters>]

paramtest -a1 -b1 [<CommonParameters>]

paramtest [-a1] [<CommonParameters>]

paramtest -a2 -b2 [<CommonParameters>]

paramtest -a2 -b1 [<CommonParameters>]

paramtest [-a2] [<CommonParameters>]

paramtest [-b1] [<CommonParameters>]

paramtest [-b2] [<CommonParameters>]
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.