PowerShell 支持变量验证脚本。这最常用于验证函数参数,但也可以应用于任何变量。每次变量值发生变化时,这些验证脚本都会运行。
# create a variable with a validation script
[ValidateScript({
if (-not ($_.Length -in @(8, 16, 24))) {
Write-Host 'Validate Failed'
throw "Value '$_' has invalid length: $($_.Length)"
} else {
Write-Host 'Validate Success'
}
$true
})][System.String]$MyValidatedArg = "a" * 8 # prints "Validate Success"
# Each one of these will trigger the validation script
Write-Host "Several valid assignments..."
$MyValidatedArg = "b" * 8 # prints "Validate Success"
$MyValidatedArg = "b" * 8 # prints "Validate Success"
$MyValidatedArg = "b" * 16 # prints "Validate Success"
$MyValidatedArg = "b" * 24 # prints "Validate Success"
如果我给变量分配一个无效值,它会引发异常
$MyValidatedArg = "foo" # throws an exception
奇怪的是,如果我在赋值过程中重新指定类型约束,就可以绕过验证脚本。我知道“别这么做”是个选择,但我的问题重点是:为什么这样做有效?
[System.String]$MyValidatedArg = "123456789" # works even though this value is invalid
起初我以为这只是一个变量遮蔽的问题。比如,我可能通过再次指定类型约束来创建第二个变量或对象之类的东西。我尝试捕获对该变量的引用,看看该引用是否会保留验证脚本。结果并没有,但我对 PowerShell 的内部机制不太熟悉,无法判断这是否是一个有效的测试。
# create a reference and assign through the reference
Write-Host "Assigning through reference..."
$refToParameter = [ref] $MyValidatedArg
$refToParameter.Value = "c" * 24 # prints "Validate Success"
Write-Host " Read via variable: $MyValidatedArg"
Write-Host " Read via reference: $($refToParameter.Value)"
# the reference and the variable are linked
# Assignments to either trigger the validation script
Write-Host "Assigning through normal variable again..."
$MyValidatedArg = "d" * 24 # prints "Validate Success"
Write-Host " Read via variable: $MyValidatedArg"
Write-Host " Read via reference: $($refToParameter.Value)"
# This works, which is odd
Write-Host "Assigning with [System.String]..."
[System.String]$MyValidatedArg = "123456789" # invalid, nothing printed
Write-Host " No exceptions yet!"
# I thought this was some sort of variable shadowing thing, but the reference shows the new value too
Write-Host "The link between the variable and the reference is still there..."
$MyValidatedArg = "e" * 8 # valid, nothing printed
Write-Host " Read via variable: $MyValidatedArg"
Write-Host " Read via reference: $($refToParameter.Value)"
# and now we appear to have killed the validation script
Write-Host "Regular invalid assignment..."
$MyValidatedArg = "123456789" # invalid, nothing printed
Write-Host " It works now for some reason"