有关 OP 方法问题的解释,请参见底部。
要准确获得您要的内容,您必须使用以下内容:
# - Make sure that parameters are NON-positional unless explicitly marked otherwise.
# - Specify the default parameter set.
[CmdletBinding(PositionalBinding=$False, DefaultParameterSetName='MultiUserA')]
Param(
# Belongs to all parameter sets.
[Parameter(Mandatory, Position=1)]
[string]$Token,
# Mandatory and positional both when combined with -GroupA or -GroupB.
[Parameter(Mandatory, Position=2, ParameterSetName='MultiUserA')]
[Parameter(Mandatory, Position=2, ParameterSetName='MultiUserB')]
[string] $UsernamesFile,
# Mandatory - but not positional - both when combined with -GroupA or -GroupB.
[Parameter(Mandatory, ParameterSetName='SingleUserA')]
[Parameter(Mandatory, ParameterSetName='SingleUserB')]
[string] $SingleUsername,
# Mandatory, whether combined with -UsernamesFile or -SingleUsername
[Parameter(Mandatory, ParameterSetName='SingleUserA')]
[Parameter(Mandatory, ParameterSetName='MultiUserA')]
[switch] $GroupA,
# Mandatory, whether combined with -UsernamesFile or -SingleUsername
[Parameter(Mandatory, ParameterSetName='SingleUserB')]
[Parameter(Mandatory, ParameterSetName='MultiUserB')]
[switch] $GroupB,
# Belongs to all parameter sets. Non-mandatory by default.
[switch] $SpecialCase
)
如你看到的,
当您使用-?
(或将其传递给Get-Help
)调用脚本时,您将看到生成的语法图:
script.ps1 [-Token] <string> [-UsernamesFile] <string> -GroupA [-SpecialCase] [<CommonParameters>]
script.ps1 [-Token] <string> [-UsernamesFile] <string> -GroupB [-SpecialCase] [<CommonParameters>]
script.ps1 [-Token] <string> -SingleUsername <string> -GroupB [-SpecialCase] [<CommonParameters>]
script.ps1 [-Token] <string> -SingleUsername <string> -GroupA [-SpecialCase] [<CommonParameters>]
但是,由于以下原因,这种方法是不明智的:
您不应该有强制 [switch]
参数,因为它们根据定义是optional。
当您为交互式参数输入调用不带参数的脚本时,PowerShell 不会让您指定开关值(我尝试过的没有值:not true
, false
, 1
, 0
, ... - try with ./script someToken someFile
)
./script.ps1 someToken -SingleUsername someUser
给出一个通用的错误消息 ( Parameter set cannot be resolved using the specified named parameters.
) 而不是特别指出缺少-GroupA
or -GroupB
,因为 PowerShell 无法知道您的意思是参数集SingleUserA
还是SingleUserB
.
- 相比之下,
./script someToken someFile
- 隐含-UsernamesFile
- 是明确的,因为MultiUserA
它是默认参数集,但由于-GroupA
开关是强制的,你仍然会得到它的值的提示)。
最后但同样重要的是,正如Mathias R. Jessen指出的那样,使用不同的、互斥的开关(-GroupA
vs. -GroupB
)不能很好地扩展,因为-Group*
快速添加更多开关会使组合的数量必须反映在它们自己的参数集中难以管理 - 请参阅下文了解如何避免这种情况。
正如Mathias R. Jessen 的有用答案中所指出的,更好的方法是对目标组使用单个参数,该参数只接受给定值集中的一个值,这[ValidationAttribute]
可以确保:
[CmdletBinding(PositionalBinding=$False, DefaultParameterSetName='MultiUser')]
Param(
[Parameter(Mandatory, Position=1)]
[string] $Token,
[Parameter(Mandatory, Position=2, ParameterSetName='MultiUser')]
[string] $UsernamesFile,
[Parameter(Mandatory, ParameterSetName='SingleUser')]
[string] $SingleUsername,
# Single -Group parameter that only accepts values 'GroupA' and 'GroupB'
# Input validation is case-INsensitive, as usual.
[Parameter(Mandatory)]
[ValidateSet('GroupA', 'GroupB')]
[string] $Group,
[switch] $SpecialCase
)
这为我们提供了以下语法图(请注意,未反映有效值的集合-Group
):
script.ps1 [-Token] <string> [-UsernamesFile] <string> -Group <string> [-SpecialCase] [<CommonParameters>]
script.ps1 [-Token] <string> -SingleUsername <string> -Group <string> [-SpecialCase] [<CommonParameters>]
这将所需参数集的数量减少到2 个。
它支持组名称的交互式输入(尽管有些不幸的是,提供无效名称会中止调用)。
如果省略-Group
, the./script.ps someToken someFile
和./script.ps someToken -SingleUserName someUser
now 的行为相同:它们提示输入-Group
值。
虽然在调用时必须键入-Group
和值可能比使用不同的开关-GroupA
和要麻烦一些-GroupB
,
- 如果组的数量随着时间的推移而增加,这是一种更可扩展的方法,
- 制表符完成确实可以扩展/循环通过有效值。
至于您原始方法的问题:
正如Clijsters指出的那样,您调用的尝试./script.ps1 -Token a -UsernamesFile someFile -GroupA
失败了,因为:
默认情况下,所有非开关参数都是位置 的- 除非您明确禁用它- 然后只有显式标记有属性的单个属性才会成为位置。[CmdletBinding(PositionalBinding=$False,...)]
[Parameter(...)]
Position
[switch]
此外,设置参数positional是没有意义的,因为它们根据定义是非位置的:您总是必须指定它们的名称(明确地),这样它们就可以放置在任何地方。