powershell - 参数-需要一些而不是其他-正确使用参数集

标签 powershell parameter-passing 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
)

但是,如果我想对此进行扩展,以便如上所述,您必须指定一个 token ,然后必须指定一个用户名文件一个用户名文件,但是现在我想指定一个用户所属的组。

现在让我们假设用户必须进入两个组之一,而我不想担心以不同的方式处理用户可能输入的组名,因此我使用两个开关。我只希望用户位于一个组中,而不是两个组中,因此开关应位于相同的位置,但应位于不同的参数集中(基于我所读的内容以及以上示例的工作原理)。

所以我的第二个例子看起来像这样-
[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
)

这不能按预期工作,但是,这给了我一个错误-

New Parameters Can't Be Found

有人可以解释为什么这行不通并更正我对PowerShell参数的理解吗?

谢谢!

最佳答案

请参阅底部以获取关于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个参数集,在此指定的任何其他属性MandatoryPosition,...-仅在给定参数集的上下文中适用于该参数。

  • 当您使用-?调用脚本(或将其传递给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]参数,因为根据定义它们是可选的。
  • 当您调用不带参数的脚本进行交互式参数输入时,PowerShell将不允许您指定开关值(没有尝试过的值:不是truefalse10,...-尝试使用./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是默认参数集,但是由于-GroupA开关是强制性的,因此仍然会提示您输入其值。
  • 最后但并非最不重要的一点,正如Mathias R. Jessen所指出的那样,使用不同的互斥开关(-GroupA-GroupB)不能很好地扩展,因为快速添加更多的-Group*开关会使必须分别反射(reflect)在自己参数中的组合数量设置难以管理-请参阅下文了解如何避免这种情况。


  • Mathias R. Jessen's helpful answer所指出的,更好的方法是对目标组使用单个参数,即仅接受给定值中的值,[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
    
    )
    

    这为我们提供了以下语法图(请注意,未反射(reflect)-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稍微麻烦一些,
  • 是更可扩展的方法,如果组的数量随时间增长,
  • 选项卡补全确实可以扩展/循环显示有效值。


  • 至于您的原始方法的问题:
  • 正如Clijsters所指出的,您尝试调用./script.ps1 -Token a -UsernamesFile someFile -GroupA的尝试失败,因为:
  • PowerShell需要明确地将给定的参数组合解析为参数集。
  • -GroupA仅属于参数集GroupA,而-UsersnameFile仅属于参数集MultiUser,因此这些参数实际上是互斥的,PowerShell无法确定要使用的参数集。
  • 默认情况下,所有非开关参数均为位置参数-除非您使用[CmdletBinding(PositionalBinding=$False,...)]显式停用它,否则只有显式标记为[Parameter(...)]属性的各个Position属性才变为位置参数。
  • 另外,将[switch]参数设置为无位置是没有意义的,因为根据定义它们是非位置的:您必须始终(明确地)指定其名称,并且可以将它们放置在任何位置。
  • 关于powershell - 参数-需要一些而不是其他-正确使用参数集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43018188/

    相关文章:

    powershell - PowerShell 中的 ParameterSetName 检测是否匹配 ValueFromPipeline 输入对象类型?

    c# - 使用 Func<T,bool>[] 作为参数列表并检查每个函数的结果

    javascript - 通过 URL 参数在远程页面上设置 Iframe 源

    powershell - 如何更改参数的抛出消息?

    powershell - 使用 powershell 将现有 API 添加到 Azure API 管理服务

    python - 在 luigi 中处理很多参数

    PowerShell 无法确定正在使用的参数集

    json - Azure Devops - 从一个任务输出 Json 对象并在另一任务中使用

    json - 在运行时从 JSON 对象中提取值

    powershell - 模块未永久加载