2

所以我正在尝试使用 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 参数的理解吗?

谢谢!

4

2 回答 2

3

有关 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]参数,因为它们根据定义是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.) 而不是特别指出缺少-GroupAor -GroupB,因为 PowerShell 无法知道您的意思是参数集SingleUserA还是SingleUserB.

    • 相比之下,./script someToken someFile- 隐含-UsernamesFile- 是明确的,因为MultiUserA它是默认参数集,但由于-GroupA开关是强制的,你仍然会得到它的值的提示)。
  • 最后但同样重要的是,正如Mathias R. Jessen指出的那样,使用不同的、互斥的开关(-GroupAvs. -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 someUsernow 的行为相同:它们提示输入-Group值。

  • 虽然在调用时必须键入-Group 值可能比使用不同的开关-GroupA和要麻烦一些-GroupB

    • 如果组的数量随着时间的推移而增加,这是一种更可扩展的方法,
    • 制表符完成确实可以扩展/循环通过有效值。

至于您原始方法的问题

  • 正如Clijsters指出的那样,您调用的尝试./script.ps1 -Token a -UsernamesFile someFile -GroupA失败了,因为:

    • PowerShell 需要明确地将给定的参数组合解析为参数集。

    • -GroupA only属于 parameter set GroupA,而-UsersnameFile only属于 parameter set MultiUser,因此这些参数实际上是互斥的,PowerShell无法确定使用哪个参数集。

  • 默认情况下,所有非开关参数都是位置 的- 除非您明确禁用它- 然后只有显式标记有属性的单个属性才会成为位置。[CmdletBinding(PositionalBinding=$False,...)][Parameter(...)]Position

  • [switch]此外,设置参数positional是没有意义的,因为它们根据定义是非位置的:您总是必须指定它们的名称(明确地),这样它们就可以放置在任何地方。

于 2017-03-25T17:02:15.297 回答
1

我将合并这两个开关并根据您希望它们进入的组进行输入。

您可以使用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
)
于 2017-03-25T15:53:06.657 回答