Writing to error stream in Powershell using Write-Error

50.2k views Asked by At

Why isn't Powershell's Write-Error cmdlet working for me? My output doesn't look like the examples in the documentation:

PS C:\> Write-Error "This is an error"
Write-Error "This is an error" : This is an error
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

I had been expecting output similar to Write-Warning:

PS H:\> Write-Warning "This is a warning"
WARNING: This is a warning

From the Write-Error and about_preference_variables documentation I thought I should not see any exceptions?

PS H:\> Get-Help About_Preference_Variables

$ErrorActionPreference
----------------------

...

        PS> $erroractionpreference                      
        Continue        # Display the value of the preference.                

        PS> write-error "Hello, World"                  
                                # Generate a non-terminating error.

        write-error "Hello, World" : Hello, World       
                                # The error message is displayed and
                                  execution continues.

        PS> write-error "Hello, World" -ErrorAction:SilentlyContinue
                                # Use the ErrorAction parameter with a 
                                  value of "SilentlyContinue".
        PS>                                             
                                # The error message is not displayed and
                                  execution continues.
4

There are 4 answers

3
Neil On BEST ANSWER

To get output similar to write-warning, you can do this:

$Host.UI.WriteErrorLine("This is an error")

(props to Chris Sears for this answer)

0
Keith Hill On

Why don't you think it is working? Keep in mind that PowerShell distinguishes between non-terminating errors like the one above and terminating errors like you get when you execute throw 'Access denied.'. Non terminating errors are written to stderr and logged in the $error collection but they don't stop processing of a script. This feature is extremely handy when you are processing (say deleting or copying) a bunch of files. You want to know which files couldn't be processed but you don't want the entire operation to stop on the first file that errors out.

PowerShell also gives you the option to "convert" non-terminating errors to terminating errors e.g.

Remove-Item c:\file-doesnt-exist -ErrorAction Stop; "Did I get here"

Notice in this case, execution stops and doesn't print out the string at the end. Try it without the -ErrorAction Stop and you will see the error but you will also see the string "Did I get here".

If you want to control the Catogory info you can use the -Category parameter like so:

PS> write-error "foo" -Category 'InvalidResult'
write-error "foo" -Category 'InvalidResult' : foo
    + CategoryInfo          : InvalidResult: (:) [Write-Error], WriteErrorExce..
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

But the WriteErrorException is the mechanism (I think) by which this cmdlet raises the error. There is an Exception parameter but I've not had much luck using it.

3
Toby Meyer On

I believe you're seeing the expected output from that cmdlet. You're inputting the "Access denied." argument and it's outputting that to the host and most likely to the error stream as designed. You can confirm it is outputting to the $Error variable and it should be populated with the error you just inserted.

i.e.

PS C:\> $error.Clear()

PS C:\> Write-Error "access denied"

Write-Error "access denied" : access denied

    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

PS C:\> $error

Write-Error "access denied" : access denied

    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

I can see where that would be confusing though, perhaps MSFT should change the example error from something like "Access Denied" to "Foobar" for clarity.

Edit to address further question: The default errorAction for Write-Error is "continue", so to get it to behave like Write-Warning you would have to add -ErrorAction SilentlyContinue. Consider the following example:

PS E:\> $error.clear()
PS E:\> Write-Error 'test'
Write-Error 'test' : test
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

PS E:\> Write-Error 'test2' -ErrorAction silentlycontinue  

PS E:\> $error[1]
Write-Error 'test' : test
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

PS E:\> $error[0]
Write-Error 'test2' -ErrorAction silentlycontinue : test2
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
0
Luke Puplett On

The problem here is that we've assumed a pattern for printing verbose, information, warning and error messages and expect the Write- cmdlets to form a set that follow this pattern.

But Write-Error is different and throws into doubt whether such a pattern was intended by the authors or was merely in the mind of the programmer. It's the Gaslighting of API design.

Write-Verbose

The Write-Verbose cmdlet writes text to the verbose message stream in PowerShell

Write-Warning

The Write-Warning cmdlet writes a warning message to the PowerShell host.

Write-Error

The Write-Error cmdlet declares a non-terminating error.

Oh. It does something different. It "declares" an error. It's like raising an event. It isn't writing text to standard error....