powershell

Using multiple PowerShell parameter sets simultaneously


I'd like to be able to use multiple parameter sets at the same time. Here's what I have so far:

# Parameter set for building binaries
[Parameter(ParameterSetName = 'Build', Mandatory = $true)]      
[bool]$BuildBinaries,
[Parameter(ParameterSetName = 'Build', Mandatory = $true)]
[string]$BuildScriptPath = "~/folder/buildscript",

# Parameter set for setting permissions on the binaries
[Parameter(ParameterSetName = 'Permission', Mandatory = $true)]      
[bool]$SetPermissions,
[Parameter(ParameterSetName = 'Permission', Mandatory = $true)]
[string]$OwnerName
  1. If I use the -BuildBinaries parameter and set it to $True, the -BuildScriptPath parameter should also be required. I'd like to be able to use these 2 parameters without the other two.
  2. If I use the -SetPermissions parameter and set it to $true, the -OwnerName parameter should be required. I'd like to be able to use these 2 parameters without the other two.
  3. I'd like to be able to use both -BuildBinaries and set it to $true (which means -BuildScriptPath should be required) and -SetPermissions and set it to $true (which means -OwnerName should be required) at the same time.

I think the above works for #1 and #2 but not 3. When I try that, I get "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."


Solution

  • Answer provided follows the most commonly used pattern for build scripts. Instead of having these two bool parameters -BuildBinaries and -SetPermissions which by themselves are anti-pattern in PowerShell, [bool] parameters can always be replaced by [switch] parameters, you can have a single -Task param that takes string[] and is decorated with a ValidateSet for every possible task in your script. Then if you need further validation you can do it in the body of your script, for example:

    function build {
        param(
            [Parameter()]
            [ValidateNotNullOrEmpty()]
            [string] $BuildScriptPath = '~/folder/buildscript',
    
            [Parameter()]
            [ValidateNotNullOrEmpty()]
            [string] $OwnerName,
    
            [Parameter()]
            [ValidateSet('Build', 'SetOwner')]
            [string[]] $Task = 'Build'
        )
    
        switch ($Task) {
            Build {
                Write-Verbose 'Running Build Task...' -Verbose
                $BuildScriptPath
                # do build stuff
            }
            SetOwner {
                Write-Verbose 'Running SetOwner Task...' -Verbose
                if ([string]::IsNullOrWhiteSpace($OwnerName)) {
                    throw [System.ArgumentNullException]::new(
                        'OwnerName',
                        "'OwnerName' parameter is required when Task is 'SetOwner'")
                }
                # do set owner stuff
            }
        }
    }
    
    build -Task SetOwner                       # Should throw
    build -OwnerName foo -Task SetOwner        # Works
    build -Task Build                          # Works because BuildScriptPath has a default value
    build -Task Build, SetOwner                # Should throw
    build -OwnerName foo -Task Build, SetOwner # Works