在脚本退出之前,Write-Error不会打印到控制台

时间:2016-02-19 02:40:42

标签: powershell

假设你有两个脚本,

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

1 个答案:

答案 0 :(得分:2)

原因是因为您在scriptblock上使用.invoke()。 .invoke()返回PSObjects的集合。根据我的理解,写入输出管道的所有数据都会返回给调用者;例如:{"a"}.invoke()将返回“a”,但是,由于某种原因,错误管道的内容被吃掉或丢弃(不知道为什么??)。

您可以使用调用运算符&修复脚本。因此,在$action.Invoke()中将& $action更改为outer.ps1可以解决您的问题。

注意:您仍然可以使用.invoke()$error内获取错误,因为 - {write-error "a"}.invoke(); $error