illegal-immigrant
illegal-immigrant

Reputation: 8224

Write-Error does not print to console before script exits

Say you have two scripts,

outer.ps1

function Main()
{
    Write-Host "starting outer"
    TryRun "outer" {
        & $PSScriptRoot\inner.ps1
    }
}

Main

and inner.ps1

function ThrowError()
{
    throw "Error"
}

function Main()
{
    Write-Host "starting inner"
    TryRun "inner" { 
        ThrowError 
    }
}

Main

where TryRun is defined same in both and defined as:

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
    }
}

Now, the problem is, when you execute outer.ps1, the output is:

starting outer
starting inner
<exception should have been printed here, but it was not>
'outer' successfully finished

However, starting inner.ps1 directly proves, it's behaving as expected:

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)
   ...

And what's more funny - if you change Write-Error to Write-Host and execute outer.ps1 the exception is getting printed

I also tried flushing Console.Out, etc buffers before doing Exit, but that did not help

Now, why is it behaving like that? What is the reason PS is not outputting exception before exit? Debugging session shows it always gets into catch and executes that Write-Error

Upvotes: 2

Views: 759

Answers (1)

Antony Thomas
Antony Thomas

Reputation: 3686

The reason is because you are using .invoke() on a scriptblock. .invoke() returns a collection of PSObjects. From what I understand, all data written into the output pipe is returned back to the caller; Eg: {"a"}.invoke() will return "a" , however, for some reason the contents of the error pipe is eaten or discarded (not sure why??).

You can fix your script by using the call operator &. So changing $action.Invoke() to & $action in outer.ps1 should fix your problem.

Note: You should still be able to get error inside .invoke() using $error as in - {write-error "a"}.invoke(); $error

Upvotes: 2

Related Questions