Outputting Errors: Write-Host/Write-Warning vs Write-Error

I ran into a curious behavior today on how errors are written to the console. Given my example below, I would expect the $err.ErrorRecord to be written the same way regardless of whether write-host/warning/error is used.

function Run-Error() {
    try {
        $os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName "fake" -ErrorAction Stop -ErrorVariable err
    } catch {
        Write-Host "---Wrote to host---" -ForegroundColor Cyan
        Write-Host $err.ErrorRecord
        Write-Host "---Wrote to Warning---" -ForegroundColor Cyan
        Write-Warning $err.ErrorRecord
        Write-Host "---Wrote to error---" -ForegroundColor Cyan
        Write-Error $err.ErrorRecord
    }
}

Run-Error

However, I get the following output:

---Wrote to host---
The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
---Wrote to Warning---
WARNING: The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
---Wrote to error---
Run-Error : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At C:\git\powershell-training\main.ps1:21 char:1
+ Run-Error
+ ~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Run-Error

Since I’m writing the same variable, I would expect the same results. I also found this strange because evaluating $err.ErrorRecord in the debugger produces output similar to Write-Error. However, if I do $err.ErrorRecord.ToString() in the debug console, I get ‘The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)’, consistent with Write-Host/Warning
Why are the outputs for these fomatted differently?

Well… you’re just not understanding how the host application treats those different pipelines ;). Host isn’t a pipeline; it’s pixels drawn directly on the screen. So, in order to achieve that, the error record has to be rendered into text. The Warning pipeline, similarly, only accepts text, and so it undergoes the same process - but “WARNING” gets pre-pended due to hard coded host behavior.

The error pipeline is entirely different. Writing to it produces an error. So you’re seeing the text you put into the error stream, but then you’re seeing the result of the host receiving an error which was not handled. So, you’re not “displaying the error” per se, you’re throwing a new exception.