无法在 Validateset 中使用预定义数组 - Powershell

bar*_*per 7 powershell validateset

我正在寻找一种方法来制作接收参数的 cmdlet,并且在键入时,它会根据预定义的选项数组提示完成建议。

我正在尝试这样的事情:

$vf = @('Veg', 'Fruit')
function Test-ArgumentCompleter {
  [CmdletBinding()]
    param (
          [Parameter(Mandatory=$true)]
          [ValidateSet($vf)]
          $Arg
    )
}
Run Code Online (Sandbox Code Playgroud)

预期结果应该是:
在编写“Test-ArgumentCompleter F”时,单击 tub 按钮后,F 自动完成为 Fruit。

mkl*_*nt0 7

  • PowerShell 通常要求属性属性是文字(例如,'Veg')或常量(例如,$true)。

  • 动态功能需要使用脚本块(本身指定为文字, { ... })或在特定情况下使用类型文字

  • 但是,该[ValidateSet()]属性仅接受字符串(按需化)文字数组或 - 在PowerShell (Core) v6 及更高版本中-类型文字(见下文)。


更新


要基于非文字值数组获得所需的功能,您需要组合其他两个属性:

# The array to use for tab-completion and validation.
[string[]] $vf = 'Veg', 'Fruit'

function Test-ArgumentCompleter {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    # Tab-complete based on array $vf
    [ArgumentCompleter(
      { param($cmd, $param, $wordToComplete) $vf -like "$wordToComplete*" }
    )]
    # Validate based on array $vf.
    # NOTE: If validation fails, the (default) error message is unhelpful.
    #       Unfortunately, this cannot be helped in *Windows PowerShell*, but in
    #       PowerShell (Core) 7+, you can add an `ErrorMessage` property:
    #         [ValidateScript({ $_ -in $vf }, ErrorMessage = 'Unknown value: {0}')]
    [ValidateScript( { $_ -in $vf })]
    $Arg
  )

  "Arg passed: $Arg"
}
Run Code Online (Sandbox Code Playgroud)


iRo*_*Ron 7

为了补充@mklement0@Mathias的答案,使用动态参数

$vf = 'Veg', 'Fruit'

function Test-ArgumentCompleter {
    [CmdletBinding()]
    param ()
    DynamicParam {
        $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
        $ParameterAttribute.Mandatory = $true
        $AttributeCollection.Add($ParameterAttribute)
        $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($vf)
        $AttributeCollection.Add($ValidateSetAttribute)
        $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter('Arg', [string], $AttributeCollection)
        $RuntimeParameterDictionary.Add('Arg', $RuntimeParameter)
        return $RuntimeParameterDictionary
    }
}
Run Code Online (Sandbox Code Playgroud)

根据您希望如何预定义参数值,您还可以使用动态 validateSet 值

Class vfValues : System.Management.Automation.IValidateSetValuesGenerator {
    [String[]] GetValidValues() { return 'Veg', 'Fruit' }
}

function Test-ArgumentCompleter {
[CmdletBinding()]
param (
        [Parameter(Mandatory=$true)]
        [ValidateSet([vfValues])]$Arg
    )
}
Run Code Online (Sandbox Code Playgroud)

注:IValidateSetValuesGenerator[read: interface]是在PowerShell的6.0中引入


Mat*_*sen 6

除了mklement0的出色答卷,我觉得有义务指出,在5及以上版本,你有一个稍微简单的替代方法可供选择:enum

一个enum,或一个“枚举类型”,是标签的静态列表与下面积分值(数字)相关联的(字符串) -和通过约束一个参数来枚举类型,PowerShell中会自动验证针对它的输入值并提供参数完成:

enum MyParameterType
{
  Veg
  Fruit
}

function Test-ArgumentCompleter {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [MyParameterType]$Arg
    )
}
Run Code Online (Sandbox Code Playgroud)

尝试使用 tab 完成参数-Arg现在将循环抛出匹配的有效枚举标签MyParameterType

enum MyParameterType
{
  Veg
  Fruit
}

function Test-ArgumentCompleter {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [MyParameterType]$Arg
    )
}
Run Code Online (Sandbox Code Playgroud)