在ValidateSet中查找值

Dar*_*te1 5 powershell

我想知道是否有检索子句中使用的值的方式Param()进行ValidateSet.像这样的东西会很棒:

Function Foo {
    Param (
        [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
        [String]$Type = 'Startup'
    )

    $Type.ValidateSet
}
Run Code Online (Sandbox Code Playgroud)

但当然Type对象上没有这样的属性.是否可以检索设置的值ValidateSet

Dav*_*ant 6

function Foo {
    param (
        [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
        [String]$Type = 'Startup'
    )

    $ParameterList = (Get-Command -Name $MyInvocation.MyCommand).Parameters
    $ParameterList["Type"].Attributes.ValidValues
}
Run Code Online (Sandbox Code Playgroud)

你的评论后:

param (
        [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
        [String]$Type = 'Startup'
)


(Get-Variable "Type").Attributes.ValidValues
Run Code Online (Sandbox Code Playgroud)

Get-Variable调用也适用于函数.


mkl*_*nt0 5

以下所有解决方案均可在功能脚本中使用.

最强大的解决方案应该适用于任何调用方案,PSv2 +:

param (
    [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
    [String]$Type = 'Startup'
)

($MyInvocation.MyCommand.Parameters['Type'].Attributes |
  Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues
Run Code Online (Sandbox Code Playgroud)

一个更简单但易碎的PSv3 +解决方案,它假定:

  • Set-StrictMode要么设置-version 1或不设置.

    • Set-StrictMode可能已设置在您的控件之外,因此如果您不完全控制执行环境,则使用上面更详细的PSv2兼容命令会更安全.
      (该Set-StrictMode设置的行为类似于变量:它由后代作用域继承,但在后代作用域中设置它会在本地设置它(仅影响作用域及其后代).)

    • 但是,如果你定义一个函数作为的一部分模块,外界的Set-StrictMode设置不会适用.

  • 至少至少Windows PowerShell v5.1/PowerShell Core v6.0-alpha16,在重复点源脚本时遇到此错误并不是一个问题.

param (
    [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
    [String]$Type = 'Startup'
)

(Get-Variable Type).Attributes.ValidValues
Run Code Online (Sandbox Code Playgroud)

可选的背景信息

PSv3 +速记语法(Get-Variable Type).Attributes.ValidValues基本上相当于:

(Get-Variable Type).Attributes | ForEach-Object { $_.ValidValues }
Run Code Online (Sandbox Code Playgroud)

也就是说,PowerShell会自动枚举集合 .Attributes并收集每个元素 .ValidValues属性的值.

在本案例中,集合中只有一个属性.Attributes- 子类型[System.Management.Automation.ValidateSetAttribute]- 具有.ValidValues属性,因此返回单个值.

鉴于其他属性没有此类属性,设置Set-StrictMode-version 2或更高会导致尝试访问不存在的属性以引发错误,并且命令失败.

((Get-Variable Type).Attributes |
  Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues
Run Code Online (Sandbox Code Playgroud)

通过明确地定位已知具有属性的一个感兴趣的属性(使用-is运算符来按类型识别)来绕过此问题.ValidValues.

于访问参数[变量]的属性的更详细的替代$Type(Get-Variable Type).Attributes是使用$MyInvocation.MyCommand.Parameters['Type'].Attributes.

使用该$MyInvocation.MyCommand.Parameters集合可以枚举和检查所有参数,而无需事先知道其名称.


David Brabant的回答很有帮助,但(撰写本文时):

  • 它可能会产生错误的印象,即脚本和函数需要单独的方法.

  • Get-Command -Name $MyInvocation.MyCommand部分是:

    • 不必要的,因为$MyInvocation.MyCommand 它本身提供相关信息:
      $MyInvocation.MyCommand是类型的实例[System.Management.Automation.ExternalScriptInfo]脚本和类型[System.Management.Automation.FunctionInfo]功能,这两者从类型派生[System.Management.Automation.CommandInfo],这是该类型Get-Commmand返回-所以他们不仅提供相同的信息,他们也明确请参阅附带的脚本/功能.

    • 脆的:

      • $MyInvocation.MyCommand被转换成字符串,由于被传递给至-Name参数,其在脚本导致脚本的单纯的文件名(例如,script.ps1),和在一个功能中的功能的名称(例如,Foo).

      • 脚本中,这通常会导致Get-Command根本找不到脚本 - 除非该脚本恰好位于PATH(其中列出的目录之一$env:PATH)中.但这也意味着碰巧具有相同文件名且恰好在PATH中首先出现的不同脚本可能会匹配,从而产生不正确的结果.
        简而言之:Get-Command -Name $MyInvocation.MyCommand在脚本中经常会中断,当它确实返回结果时,它可能是错误的脚本.

      • 函数中,它也可以识别错误的命令,尽管这种可能性要小得多:
        由于PowerShell的命令优先级,给定的名称首先被解释为别名,然后作为函数,理论上,定义了Foo 别名,Get-Command -Name $MyInvocation.MyCommand内部函数 Foo会返回错误有关的信息的别名.
        (这是平凡到调用函数Foo,而别名Foo定义,但它可以做到的;例如:& (Get-Item Function:Foo))