参数 - 需要一些但不需要其他 - 参数集的正确使用
Parameters - Requiring Some But Not Others - Correct Use of Parameter Sets
所以我正在尝试使用 PowerShell,但在理解参数方面遇到了一些困难。根据我的阅读,如果我指定一个参数与另一个参数位于同一位置,但将其放在单独的 ParameterSet 中,PowerShell 将只需要这些参数之一。
在这个例子中按预期工作 -
[CmdletBinding(DefaultParameterSetName='MultiUser')]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Token,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="MultiUser")]
[string]$UsernamesFile,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="SingleUser")]
[string]$SingleUsername,
[Parameter(Mandatory=$False)]
[switch]$SpecialCase
)
但是如果我想对此进行扩展,那么您必须指定一个令牌,然后您必须指定一个用户名 或 用户名文件,但现在我想指定用户所在的组。
现在假设用户必须进入两个组之一,我不想担心处理用户可能输入组名的不同方式,所以我使用两个开关。我只希望用户在一个组中而不是两个组中,因此开关应该在相同的位置但在不同的参数集中(基于我读过的内容和上面的示例有效)。
所以我的第二个例子是这样的 -
[CmdletBinding(DefaultParameterSetName='MultiUser')]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Token,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="MultiUser")]
[string]$UsernamesFile,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="SingleUser")]
[string]$SingleUsername,
[Parameter(Mandatory=$True,Position=3, ParameterSetName="GroupA")]
[switch]$GroupA,
[Parameter(Mandatory=$True,Position=3, ParameterSetName="GroupB")]
[switch]$GroupB,
[Parameter(Mandatory=$False)]
[switch]$SpecialCase
)
然而,这并没有按预期工作,这给了我一个错误 -
有人可以解释为什么这不起作用并纠正我对 PowerShell 参数的理解吗?
谢谢!
我会合并这两个开关并根据您希望它们在哪个组中进行输入。
您可以使用 ValidateSet
验证属性来确保用户指定两个特定组之一
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Token,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="MultiUser")]
[string]$UsernamesFile,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="SingleUser")]
[string]$SingleUsername,
[Parameter(Mandatory=$True,Position=3)]
[ValidateSet('A','B')]
[string]$Group,
[Parameter(Mandatory=$False)]
[switch]$SpecialCase
)
见底部以了解 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
)
如您所见,
您需要定义 4 个参数集,这些参数集相当于所有 users-file-vs.-single-user 和 groupA-vs.-group-B 组合.
您需要将每个参数分配给多个个参数集,选择合适的子集。
- 请注意,每个
[Parameter(...)]
属性只能指定 1 参数集,以及您在那里指定的任何其他属性 - Mandatory
、Position
, ... - 仅在给定参数集 . 的上下文中应用于参数
当您使用 -?
调用脚本(或将其传递给 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]
参数,因为根据定义它们是可选 .
当您为 interactive 参数条目调用不带参数的脚本时,PowerShell 不会让您指定开关值(我试过的值都不起作用: 不是 true
, false
, 1
, 0
, ... - 试试 ./script someToken someFile
)
./script.ps1 someToken -SingleUsername someUser
给出一般错误消息 (Parameter set cannot be resolved using the specified named parameters.
) 而不是具体指出缺少 -GroupA
或 -GroupB
,因为 PowerShell不知道你是指参数集 SingleUserA
还是 SingleUserB
.
- 相比之下,
./script someToken someFile
- 隐含 -UsernamesFile
- 是明确的,因为 MultiUserA
是 default 参数集,但由于-GroupA
开关是 强制性的 ,您仍然会得到输入其值的提示。
最后但同样重要的是,正如 Mathias R. Jessen 指出的那样,使用不同的、互斥的开关(-GroupA
与 -GroupB
)不能很好地扩展,因为快速添加更多 -Group*
开关会使必须在各自的参数集中反映的组合数量难以管理 - 请参阅下文了解如何避免这种情况。
正如 中指出的那样,更好的方法 是使用 单个参数 对于 只接受一组给定值中的一个值的目标组 ,[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
,./script.ps someToken someFile
和 ./script.ps someToken -SingleUserName someUser
现在的行为相同:它们提示输入 -Group
值。
虽然必须键入 -Group
和 一个值在调用时可能比具有不同的开关 -GroupA
和 -GroupB
,
- 如果组的数量随着时间的推移而增加,那么它是更可扩展的方法,
- tab 完成确实可以扩展/循环显示有效值。
至于你原来的方法有问题:
正如 Clijsters 指出的那样,您尝试调用 ./script.ps1 -Token a -UsernamesFile someFile -GroupA
失败了,因为:
PowerShell 需要明确地将给定的参数组合解析为参数集。
-GroupA
只有属于参数集GroupA
,而-UsersnameFile
只有属于参数集MultiUser
,所以这些参数实际上互斥,PowerShell无法确定使用什么参数集
所有非开关参数都是位置 默认 - 除非你用[=52=明确停用它] - 然后只有单独的 [Parameter(...)]
属性明确标记为 Position
属性成为位置。
另外,[switch]
参数 positional 没有意义,因为根据定义它们是非位置的:你总是有指定它们的名称(明确),这样就可以将它们放置在任何地方。
所以我正在尝试使用 PowerShell,但在理解参数方面遇到了一些困难。根据我的阅读,如果我指定一个参数与另一个参数位于同一位置,但将其放在单独的 ParameterSet 中,PowerShell 将只需要这些参数之一。
在这个例子中按预期工作 -
[CmdletBinding(DefaultParameterSetName='MultiUser')]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Token,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="MultiUser")]
[string]$UsernamesFile,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="SingleUser")]
[string]$SingleUsername,
[Parameter(Mandatory=$False)]
[switch]$SpecialCase
)
但是如果我想对此进行扩展,那么您必须指定一个令牌,然后您必须指定一个用户名 或 用户名文件,但现在我想指定用户所在的组。
现在假设用户必须进入两个组之一,我不想担心处理用户可能输入组名的不同方式,所以我使用两个开关。我只希望用户在一个组中而不是两个组中,因此开关应该在相同的位置但在不同的参数集中(基于我读过的内容和上面的示例有效)。
所以我的第二个例子是这样的 -
[CmdletBinding(DefaultParameterSetName='MultiUser')]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Token,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="MultiUser")]
[string]$UsernamesFile,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="SingleUser")]
[string]$SingleUsername,
[Parameter(Mandatory=$True,Position=3, ParameterSetName="GroupA")]
[switch]$GroupA,
[Parameter(Mandatory=$True,Position=3, ParameterSetName="GroupB")]
[switch]$GroupB,
[Parameter(Mandatory=$False)]
[switch]$SpecialCase
)
然而,这并没有按预期工作,这给了我一个错误 -
有人可以解释为什么这不起作用并纠正我对 PowerShell 参数的理解吗?
谢谢!
我会合并这两个开关并根据您希望它们在哪个组中进行输入。
您可以使用 ValidateSet
验证属性来确保用户指定两个特定组之一
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$Token,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="MultiUser")]
[string]$UsernamesFile,
[Parameter(Mandatory=$True,Position=2, ParameterSetName="SingleUser")]
[string]$SingleUsername,
[Parameter(Mandatory=$True,Position=3)]
[ValidateSet('A','B')]
[string]$Group,
[Parameter(Mandatory=$False)]
[switch]$SpecialCase
)
见底部以了解 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
)
如您所见,
您需要定义 4 个参数集,这些参数集相当于所有 users-file-vs.-single-user 和 groupA-vs.-group-B 组合.
您需要将每个参数分配给多个个参数集,选择合适的子集。
- 请注意,每个
[Parameter(...)]
属性只能指定 1 参数集,以及您在那里指定的任何其他属性 -Mandatory
、Position
, ... - 仅在给定参数集 . 的上下文中应用于参数
- 请注意,每个
当您使用 -?
调用脚本(或将其传递给 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]
参数,因为根据定义它们是可选 .当您为 interactive 参数条目调用不带参数的脚本时,PowerShell 不会让您指定开关值(我试过的值都不起作用: 不是
true
,false
,1
,0
, ... - 试试./script someToken someFile
)./script.ps1 someToken -SingleUsername someUser
给出一般错误消息 (Parameter set cannot be resolved using the specified named parameters.
) 而不是具体指出缺少-GroupA
或-GroupB
,因为 PowerShell不知道你是指参数集SingleUserA
还是SingleUserB
.- 相比之下,
./script someToken someFile
- 隐含-UsernamesFile
- 是明确的,因为MultiUserA
是 default 参数集,但由于-GroupA
开关是 强制性的 ,您仍然会得到输入其值的提示。
- 相比之下,
最后但同样重要的是,正如 Mathias R. Jessen 指出的那样,使用不同的、互斥的开关(
-GroupA
与-GroupB
)不能很好地扩展,因为快速添加更多-Group*
开关会使必须在各自的参数集中反映的组合数量难以管理 - 请参阅下文了解如何避免这种情况。
正如 [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
,./script.ps someToken someFile
和./script.ps someToken -SingleUserName someUser
现在的行为相同:它们提示输入-Group
值。虽然必须键入
-Group
和 一个值在调用时可能比具有不同的开关-GroupA
和-GroupB
,- 如果组的数量随着时间的推移而增加,那么它是更可扩展的方法,
- tab 完成确实可以扩展/循环显示有效值。
至于你原来的方法有问题:
正如 Clijsters 指出的那样,您尝试调用
./script.ps1 -Token a -UsernamesFile someFile -GroupA
失败了,因为:PowerShell 需要明确地将给定的参数组合解析为参数集。
-GroupA
只有属于参数集GroupA
,而-UsersnameFile
只有属于参数集MultiUser
,所以这些参数实际上互斥,PowerShell无法确定使用什么参数集
所有非开关参数都是位置 默认 - 除非你用[=52=明确停用它] - 然后只有单独的
[Parameter(...)]
属性明确标记为Position
属性成为位置。另外,
[switch]
参数 positional 没有意义,因为根据定义它们是非位置的:你总是有指定它们的名称(明确),这样就可以将它们放置在任何地方。