提问人:JHR 提问时间:9/27/2023 最后编辑:JHR 更新时间:9/30/2023 访问量:84
PowerShell 无法根据位置参数的数量选取正确的 ParameterSet
PowerShell fails to pick correct ParameterSet based on number of positional parameters
问:
我正在尝试编写一个PowerShell函数,该函数使用ParameterSets公开其可用参数。我希望该函数具有类似于以下内容的参数集:Set-MyRef
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>
也就是说,恰好是其中一个选项,或者可以给出一个选项,并将可选作为第一个位置参数。
重要的是,我希望被解析为 ,并被解析为 。-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 }"
}
这给出了正确的解析语法:
$ 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>]
但无法正确解析参数。当仅使用一个位置参数调用它时,它会将其用于 和 :$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 }
如何更改我的 ParameterSet 规范,以便在仅给出一个位置参数时 PowerShell 可以正确选取 ParameterSet?Set-MyRef [Tag] <string>
答:
6赞
mklement0
9/28/2023
#1
看起来您遇到了一个错误,其中单个位置参数被错误地绑定到 和 ,似乎是由于两者都具有参数属性属性,尽管这些属性属于不同的参数集。-Tag
-Env
Position=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 }"
}
- 否则,解决方法会变得很麻烦:
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 }"
}
注意:
- 上面假设没有合法的用例,其中 and 参数恰好具有相同的值。通过更多的努力,后一种情况也可以得到处理。
-Env
-Target
- 上面假设没有合法的用例,其中 and 参数恰好具有相同的值。通过更多的努力,后一种情况也可以得到处理。
评论
0赞
JHR
9/28/2023
虽然这修复了单参数情况,但不幸的是,它看起来在双参数情况下交换了 / 参数:应该解析为 ,但被解析为 '-Env 'bar' -Tag 'foo'。-Tag
-Env
Set-MyRef 'foo' 'bar'
-Env 'foo' -Tag 'bar'
0赞
JHR
9/28/2023
我假设否定是未定义的行为,因为我在任何文档中都找不到它(并且在运行时会导致错误)。不过,这是一个巧妙的技巧!Position
Get-Command Set-MyRef -Syntax
0赞
mklement0
9/28/2023
好点,@JHR;我已经更新了答案,以注意到建议的解决方法不是其中之一。我会再考虑一下。
0赞
mklement0
9/28/2023
@JHR,请查看我的更新是否有帮助。
1赞
mklement0
9/30/2023
很高兴听到它,@JHR;别客气。我创建了 GitHub 问题 #20405 来讨论意外行为。
评论