PowerShell 无法根据位置参数的数量选择正确的 ParameterSet

JHR*_*JHR 5 powershell parameter-sets powershell-7

我正在尝试编写一个Set-MyRef使用 ParameterSets 来公开其可用参数的 PowerShell 函数。我希望该函数具有类似于以下内容的参数集:

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>
Run Code Online (Sandbox Code Playgroud)

也就是说,恰好有一个 options -Latest-LocalBranch或者-Tag可以给出一个可选的-Env作为第一个位置参数。
重要的是,我希望Set-MyRef 'foo'被解析为-Tag 'foo',并被Set-MyRef 'foo' 'bar'解析为-Env 'foo' -Tag 'bar'.

我尝试使用 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 }"
}
Run Code Online (Sandbox Code Playgroud)

这给出了正确的解析语法:

$ 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>]
Run Code Online (Sandbox Code Playgroud)

但无法正确解析参数。当仅使用一个位置参数调用它时,它将同时用于$Env$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 }
Run Code Online (Sandbox Code Playgroud)

Set-MyRef [Tag] <string>当仅给出一个位置参数时,如何更改 ParameterSet 规范,以便 PowerShell 可以正确选择 ParameterSet ?

mkl*_*nt0 6

看起来您遇到了一个错误,其中单个位置参数错误地绑定到 ,似乎是由于两者都具有参数属性属性-Tag,尽管这些属性属于不同的参数集-EnvPosition=0

  • 注意:虽然您的场景很不寻常,因为第一个位置参数应该绑定到哪个参数取决于目标参数集,但它在逻辑上是明确的,并且事实上的行为没有意义 - 请参阅GitHub 问题 #20405

解决方法

  • 最好将位置参数的顺序更改为绑定-Tag-Env,后绑定:
function Set-MyRef {
  [CmdletBinding(DefaultParameterSetName='Tag')]
  param (
      [Parameter(Position = 1, Mandatory, ParameterSetName = 'EnvTag')]
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'EnvLatest')]
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'EnvLocal')]
      [string]$Env,
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'Tag')]
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'EnvTag')]
      [string]$Tag,
      [Parameter(Mandatory, ParameterSetName = 'Latest')]
      [Parameter(Mandatory, ParameterSetName = 'EnvLatest')]
      [switch]$Latest,
      [Parameter(Mandatory, ParameterSetName = 'Local')]
      [Parameter(Mandatory, ParameterSetName = 'EnvLocal')]
      [switch]$LocalBranch
  )

  Write-Host "{ Env: $Env, Tag: $Tag, Latest: $Latest, LocalBranch: $LocalBranch }"
}
Run Code Online (Sandbox Code Playgroud)
  • 否则,解决方法会变得很麻烦:
function Set-MyRef {
  [CmdletBinding(DefaultParameterSetName='Env')]
  param (
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'EnvTag')]
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'EnvLatest')]
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'EnvLocal')]
      [string]$Env,
      [Parameter(Position = 0, Mandatory, ParameterSetName = 'Tag')]
      [Parameter(Position = 1, Mandatory = $false, ParameterSetName = 'EnvTag')]
      [string]$Tag,
      [Parameter(Mandatory, ParameterSetName = 'Latest')]
      [Parameter(Mandatory, ParameterSetName = 'EnvLatest')]
      [switch]$Latest,
      [Parameter(Mandatory, ParameterSetName = 'Local')]
      [Parameter(Mandatory, ParameterSetName = 'EnvLocal')]
      [switch]$LocalBranch
  )

  # Compensate for the broken parameter binding, by inferring
  # from the fact that the -Tag argument is the same as the -Env argument
  # that only *one* positional argument was passed and that it was meant to
  # bind to -Tag.
  if ($PSCmdlet.ParameterSetName -eq 'EnvTag' -and $Env -eq $Tag) {
    $Env = $null
  }
  Write-Host "{ Env: $Env, Tag: $Tag, Latest: $Latest, LocalBranch: $LocalBranch }"
}
Run Code Online (Sandbox Code Playgroud)
  • 笔记:

    • 上面假设不存在和参数碰巧具有相同值的合法用例。如果付出更多的努力,后一种情况也可以得到处理。-Env-Target