Google

2013-09-02

PowerShell try catch gotcha

I check out StackOverflow's PowerShell section time to time, and one issue seems to trip people a lot: Try/Catch block.

Here is how Try/Catch is block is constructed:


Try {
## Some code here which is likely to fail
}
Catch {
## What to do if try block has a "terminating" error
}

Here is an example:


try { get-content c:\a.txt;"file exists" }catch{"that file does not exist"}

If you run the code above; it will throw an error on the Get-Content if 'c:\a.txt' file does not exist. And in theory we should be able to catch that but that is not exactly what happens:


PS Z:\> try { get-content c:\a.txt;"file exists" }catch{"that file does not exist"}
get-content : Cannot find path 'C:\a.txt' because it does not exist.
At line:1 char:7
+ try { get-content c:\a.txt;"file exists" }catch{"that file does not exist"}
+       ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\a.txt:String) [Get-Content], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand

file exist
PS Z:\>

Did you notice that "file exist" line being printed? Umm, what happened?

Well, remember I said "terminating" errors are caught. the first line is an error but not a terminating error. And therefore, the next line is executed.

Anything we can do to stop this? Yes, use -ErrorAction after the command or $ErrorActionPreference.


PS Z:\> try { get-content c:\a.txt -ErrorAction stop; "file exists" }catch{"that file does not exist"}
that file does not exist
PS Z:\>

With ErrorAction set to STOP, the error on the first line becomes a terminating error and hence get caught in the CATCH {} block.

Similarly, we can set the $ErrorActionPreference variable before the line top "STOP"; and tell our code to treat any error as terminating one.


PS Z:\> $ErrorActionPreference="STOP"; try { get-content c:\a.txt; "file exists" }catch{"that file does not exist"}
that file does not exist
PS Z:\>

If not specified, $ErrorActionPreference is set to "Continue".


PS Z:\> $ErrorActionPreference
Continue
PS Z:\>

Note that it is not "SilentlyContinue", which would execute the next statement without complaining about the error.


PS Z:\> try { get-content c:\a.txt -ErrorAction SilentlyContinue; "file exists" }catch{"that file does not exist"}
file exist

This is equivalent to "On Error Resume Next" in vbScript.

No comments: