为什么仅在 ISE 中第一次使用 Get-Variable 访问参数变量的属性?
Why does accessing a parameter variable's attributes with Get-Variable only work the first time in the ISE?
感谢 Whosebug 的优秀人员,我们收到了关于如何在脚本或函数的 Param()
子句中检索 ValidateSet
中定义的值的非常好的 :
Param (
[ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
[String]$Type = 'Startup'
)
(Get-Variable Type).Attributes.ValidValues
唯一让我困扰的是,当您在 PowerShell ISE 中 运行 时,此代码仅在 第一次 时有效。 第二次你运行它,没有输出产生。
是否有解决方法让它始终有效?我们在 Win 7 和 Win 2012 上使用 PowerShell 4.0。
首先,此行为仅在 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
tl;dr
从 Windows PowerShell v5.1 / PowerShell 开始,观察到的行为可以说是一个 bug核心 v6.0-beta.4 - 请参阅 this GitHub issue.
要无副作用地绕过问题,请使用以下方法:
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 本身无关,而是 repeated dot-sourcing(ISE 恰好通过点源 运行 所有脚本)。
Dot-sourcing 运行s 脚本在 current 范围内(在调用者的范围内,而不是在子范围内)因此通常会修改当前范围的状态,例如通过添加变量。
如果您从交互式会话中点源脚本,您实际上是在修改全局会话状态,例如,这就是 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
感谢 Whosebug 的优秀人员,我们收到了关于如何在脚本或函数的 Param()
子句中检索 ValidateSet
中定义的值的非常好的
Param (
[ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
[String]$Type = 'Startup'
)
(Get-Variable Type).Attributes.ValidValues
唯一让我困扰的是,当您在 PowerShell ISE 中 运行 时,此代码仅在 第一次 时有效。 第二次你运行它,没有输出产生。
是否有解决方法让它始终有效?我们在 Win 7 和 Win 2012 上使用 PowerShell 4.0。
首先,此行为仅在 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
tl;dr
从 Windows PowerShell v5.1 / PowerShell 开始,观察到的行为可以说是一个 bug核心 v6.0-beta.4 - 请参阅 this GitHub issue.
要无副作用地绕过问题,请使用以下方法:
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 本身无关,而是 repeated dot-sourcing(ISE 恰好通过点源 运行 所有脚本)。
Dot-sourcing 运行s 脚本在 current 范围内(在调用者的范围内,而不是在子范围内)因此通常会修改当前范围的状态,例如通过添加变量。
如果您从交互式会话中点源脚本,您实际上是在修改全局会话状态,例如,这就是 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