为什么使用Get-Variable访问参数变量的属性仅在ISE中第一次工作?

时间:2017-03-10 07:24:10

标签: powershell reflection powershell-ise

感谢StackOverflow上的优秀人才,我们收到了关于如何在脚本或函数的ValidateSet子句中检索Param()中定义的值的非常好的answer

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

(Get-Variable Type).Attributes.ValidValues

唯一困扰我的是,当您在PowerShell ISE中运行此代码时,此代码仅适用于第一次第二次运行它,没有生成输出。

是否有解决方法让它始终有效?我们在Win 7和Win 2012上使用PowerShell 4.0。

2 个答案:

答案 0 :(得分:3)

首先,这种行为只出现在PowerShell ISE中(它在外部完美运行)。这可能由following post解释。

阅读它,您会发现有一种解决方法:

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

(Get-Variable Type).Attributes.ValidValues

# Do your stuff here

Remove-Variable Type

答案 1 :(得分:2)

<强> TL;博士

  • 从Windows PowerShell v5.1 / PowerShell Core v6.0-beta.4开始,观察到的行为可以说是 bug - 请参阅{{3} }。

  • 绕过没有副作用的问题,请使用以下方法:

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

$MyInvocation.MyCommand.Parameters['Type'].Attributes.ValidValues

如果Set-StrictMode -version 2或更高版本有效或您正在使用PSv2,请使用

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

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

可选背景信息

问题与 ISE 本身无关,而是与重复 dot-sourcing 有关(ISE恰好运行所有脚本)通过点源他们)。

this GitHub issue当前作用域中运行脚本(在调用者的作用域本身,而不是在子作用域中),因此通常会修改当前作用域的状态,例如通过添加变量。
如果您从交互式会话中点源脚本,则可以有效地修改全局会话状态,例如,加载PS配置文件中的定义的方式。

在目前的情况下,脚本的点源调用有效地将参数变量$Type作为常规添加到调用范围变量,按设计。

当您再次点源同一个脚本 时会出现错误(假设问题中的脚本显示为./script.ps1

  • 在第一次点源调用之后,变量$Type在其属性方面仍然完好无损:

    > . ./script.ps1; (Get-Variable Type).Attributes.Count
    Startup
    Shutdown
    LogOn
    LogOff
    3   # PS implicitly adds 2 add'l attributes behind the scenes
    
  • 当你再次点源 时,属性丢失

    > . ./script.ps1; (Get-Variable Type).Attributes.Count
    0