I am attempting to write a PowerShell function Set-MyRef which uses ParameterSets to expose its available parameters. I would like the function to have parameter sets similar to:
Set-MyRef -Latest
Set-MyRef -LocalBranch
Set-MyRef [-Tag] <string>
Set-MyRef [-Env] <string> -LocalBranch
Set-MyRef [-Env] <string> -Latest
Set-MyRef [-Env] <string> [-Tag] <string>
That is, exactly one of the options -Latest, -LocalBranch or -Tag may be given, with an optional -Env as first positional parameter.
Importantly, I would expect Set-MyRef 'foo' to be parsed as -Tag 'foo', and Set-MyRef 'foo' 'bar' to be parsed as -Env 'foo' -Tag 'bar'.
I attempted to implement it using ParameterSets:
function Set-MyRef {
[CmdletBinding()]
param (
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'EnvTag')]
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'EnvLatest')]
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'EnvLocal')]
[string]$Env,
[Parameter(Position = 0, Mandatory = $true, ParameterSetName = 'Tag')]
[Parameter(Position = 1, Mandatory = $true, ParameterSetName = 'EnvTag')]
[string]$Tag,
[Parameter(Mandatory = $true, ParameterSetName = 'Latest')]
[Parameter(Mandatory = $true, ParameterSetName = 'EnvLatest')]
[switch]$Latest,
[Parameter(Mandatory = $true, ParameterSetName = 'Local')]
[Parameter(Mandatory = $true, ParameterSetName = 'EnvLocal')]
[switch]$LocalBranch
)
Write-Host "{ Env: $Env, Tag: $Tag, Latest: $Latest, LocalBranch: $LocalBranch }"
}
Which gives the correct parsed syntax:
$ Get-Command Set-MyRef -Syntax
Set-MyRef [-Env] <string> -LocalBranch [<CommonParameters>]
Set-MyRef [-Env] <string> -Latest [<CommonParameters>]
Set-MyRef [-Env] <string> [-Tag] <string> [<CommonParameters>]
Set-MyRef [-Tag] <string> [<CommonParameters>]
Set-MyRef -Latest [<CommonParameters>]
Set-MyRef -LocalBranch [<CommonParameters>]
But fails to correctly parse the parameters. When calling it using only one position parameter it uses it for both $Env and $Tag:
$ Set-MyRef 'foo' # incorrect - expect Env = $null, Tag = 'foo'
{ Env: foo, Tag: foo, Latest: False, LocalBranch: False }
$ Set-MyRef -Tag 'foo' # correct
{ Env: , Tag: foo, Latest: False, LocalBranch: False }
How do I change my ParameterSet specification so PowerShell can correctly pick the Set-MyRef [Tag] <string> ParameterSet, when only one positional parameter is given?
It looks like you've run into a bug, where a single positional argument is mistakenly bound to both
-Tagand-Env, seemingly due to both having aPosition=0parameter-attribute property, despite those properties belonging to different parameter sets.Workarounds:
-Tagfirst, before-Env:Note:
-Envand-Targetarguments happen to have the same value. With substantially more effort, the latter case could be handled too.