在使用ForEach-Object调用引发终止错误的脚本时,我在一个非常特殊的情况下看到了一些奇怪的行为。
好像在某些情况下,在-Process
脚本块中终止错误不会导致整个脚本执行停止,因为我预期......无论如何都会继续执行。
在这些情况下使用ForEach-Object
(或任何cmdlet /高级功能)时,我想知道是否有任何问题。
以下示例代表了我的期望:
$childScriptPath = '.\childscript.ps1'
Set-Content $childScriptPath -Value @'
$ErrorActionPreference = 'Stop'
# normally non-terminating, but should be terminating here due
# to $ErrorActionPreference = 'Stop'
Get-Command command_that_does_not_exist
# We never get here as expected
Write-Host 'After Get-Command: should not get here'
'@
"something doesn't matter what" | ForEach-Object {
& $childScriptPath
}
# Shouldn't get here due to terminating error...works as expected.
Write-Host 'Script should have thrown a terminating error; should not get here'
以下示例不起作用,因为我期待。请注意,唯一的区别是它使用Set-StrictMode
后跟未定义变量的引用导致错误而不是使用不存在的命令调用Get-Command
:
$childScriptPath = '.\childscript.ps1'
Set-Content $childScriptPath -Value @'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version latest
# normally would silently continue, but should throw a
# terminating error here due to $ErrorActionPreference = 'Stop'
# and Set-StrictMode -Version latest
$undefinedVariable
# We never get here as expected
Write-Host 'After undefined variable: should not get here'
'@
"something doesn't matter what" | ForEach-Object {
& $childScriptPath
}
# Shouldn't get here, but it does!!!
Write-Host 'Script should have thrown a terminating error; should not get here'
如果有人有任何见解,我们将非常感激。
实际上,这似乎是cmdlet /高级功能与常规功能之间的行为差异,因为如果我们采用"不能按预期工作"上面的示例并使用手动ForEach-Object
函数作为常规非高级函数实现,它按预期工作:
$childScriptPath = '.\childscript.ps1'
Set-Content $childScriptPath -Value @'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version latest
# normally would silently continue, but should throw
# terminating error here due to $ErrorActionPreference = 'Stop'
# and Set-StrictMode -Version latest
$undefinedVariable
# We never get here as expected
Write-Host 'After undefined variable: should not get here'
'@
function ForEach-Object2 {
param (
[scriptblock]$ScriptBlock
)
process {
& $ScriptBlock
}
}
"something doesn't matter what" | ForEach-Object2 {
& $childScriptPath
}
# Shouldn't get here...works as expected.
Write-Host 'Script should have thrown a terminating error; should not get here'
另一方面,如果我们将手动ForEach-Object
函数转换为高级函数,我们会回到意外行为:
$childScriptPath = '.\childscript.ps1'
Set-Content $childScriptPath -Value @'
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version latest
# normally would silently continue, but should throw
# terminating error here due to $ErrorActionPreference = 'Stop'
# and Set-StrictMode -Version latest
$undefinedVariable
# We never get here as expected
Write-Host 'After undefined variable: should not get here'
'@
function ForEach-Object2 {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline=$true)]
[object]$InputObject,
[Parameter(Position=0)]
[scriptblock]$ScriptBlock
)
process {
& $ScriptBlock $InputObject
}
}
"something doesn't matter what" | ForEach-Object2 {
& $childScriptPath
}
# Shouldn't get here, but it does!!!
Write-Host 'Script should have thrown a terminating error; should not get here'