Search code examples
powershellwrite-error

Strange behaviour of Write-Error (PowerShell): no output from within methods with a return value


The output of Write-Error is ommited in methods that have a return value (i.e. are not void):

Class MyClass {
    [void]MethodWithoutReturnValue([string]$Msg) {
        Write-Error "MyClass.MethodWithoutReturnValue(): $Msg"
    }

    [bool]MethodWithReturnValue([string]$Msg) {
        Write-Error "MyClass.MethodWithReturnValue(): $Msg"
        $this.MethodWithoutReturnValue("this won't work either")
        return $true
    }
}

[MyClass]$obj = [MyClass]::new()
$obj.MethodWithoutReturnValue('this error will show up')
[bool]$Result = $obj.MethodWithReturnValue('this error will NOT show up')

I'm expecting three error message but only get one. Please notice that the calling the void method from the bool method also omits the output, as if the call stack is "poisoned" somehow. And yes (though not shown in this example) void method calling void method works.

Can someone please explain this behaviour or did I just find a bug?


Solution

  • There's a bug open for that currently. The problem is actually that Write-Error work in void method.

    By design, the intent is that you should use Throw to produce an error from within a class.

    Here's the modified version of your script

    Class MyClass {
        [void]MethodWithoutReturnValue([string]$Msg) {
           Throw "MyClass.MethodWithoutReturnValue(): $Msg"
        }
    
        [bool]MethodWithReturnValue([string]$Msg) {
           Throw "MyClass.MethodWithReturnValue(): $Msg"
            $this.MethodWithoutReturnValue("this won't work either")
            return $true
        }
    }
    
    [MyClass]$obj = [MyClass]::new()
    $obj.MethodWithoutReturnValue('this error will show up')
    [bool]$Result = $obj.MethodWithReturnValue('this error will NOT show up')
    

    Additional note

    Using Throw will stop your script so the script won't proceed further. To prevent that, use a Try{}Catch{} statement.

    [MyClass]$obj = [MyClass]::new()
    Try {
        $obj.MethodWithoutReturnValue('this error will show up')
        }
    Catch {
        Write-Error $_
    }
    [bool]$Result = $obj.MethodWithReturnValue('this error will NOT show up')
    
    # I love Cyan
    Write-Host 'Second error not being in a try catch mean this will not get printed' -ForegroundColor Cyan
    

    Reference

    Github -Write-Error fails to work in class methods that return a non-void value