假设你有两个脚本,
outer.ps1
function Main()
{
Write-Host "starting outer"
TryRun "outer" {
& $PSScriptRoot\inner.ps1
}
}
Main
和inner.ps1
function ThrowError()
{
throw "Error"
}
function Main()
{
Write-Host "starting inner"
TryRun "inner" {
ThrowError
}
}
Main
其中TryRun
在两者中定义相同并定义为:
function TryRun([string] $name, [scriptblock] $action)
{
try
{
$action.Invoke()
Write-Host "'$name' successfully finished"
Exit 0
}
catch [System.Exception]
{
$separator = New-Object string @("-", 120)
Write-Error "'$name' failed`n$separator`n$($_.Exception.ToString())`n$separator"
Exit 1
}
}
现在,问题是,当您执行outer.ps1
时,输出为:
starting outer
starting inner
<exception should have been printed here, but it was not>
'outer' successfully finished
然而,直接开始inner.ps1
证明,它的行为符合预期:
TryRun : 'inner' failed
-------------------------------------------------------------------------------
-----------------------------------------
System.Management.Automation.RuntimeException: Error --->
System.Management.Automation.RuntimeException: Error
--- End of inner exception stack trace ---
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(F
unctionContext funcContext, Exception exception)
...
更有趣的是 - 如果您将Write-Error
更改为Write-Host
并执行outer.ps1
,则异常 会被打印
我还尝试在Console.Out, etc
之前刷新Exit
缓冲区,但这没有帮助
现在,为什么它表现得那样? PS退出前不输出异常的原因是什么?调试会话显示它总是进入catch并执行Write-Error
答案 0 :(得分:2)
原因是因为您在scriptblock上使用.invoke()。 .invoke()返回PSObjects的集合。根据我的理解,写入输出管道的所有数据都会返回给调用者;例如:{"a"}.invoke()
将返回“a”,但是,由于某种原因,错误管道的内容被吃掉或丢弃(不知道为什么??)。
您可以使用调用运算符&
修复脚本。因此,在$action.Invoke()
中将& $action
更改为outer.ps1
可以解决您的问题。
注意:您仍然可以使用.invoke()
在$error
内获取错误,因为 - {write-error "a"}.invoke(); $error