PowerShell How-To

Understanding the Try/Catch Block in PowerShell

Try and catch blocks are designed to catch errors in your code, no matter the situation.

Error handling is important when creating PowerShell scripts. A script that runs correctly once may not run correctly every time. There always seems to be some kind of problem that crops up when you least expect it. This is why error handling should be implemented in every piece of PowerShell code you create.

A staple of error handling in PowerShell is the try and catch blocks. The try and catch blocks. more often just called a try/catch block. is a construct that implements a "net" of sorts to catch errors in your code. To be more specific, when an exception is thrown anywhere inside of a try block, there's a catch block that's there to catch the thrown exception and do something with it. In PowerShell, an exception is a terminating error.

There are many uses of a try/catch block, but a common one is being placed inside of a function to catch any terminating errors that may come up inside of the function. Perhaps I have a function that I have added a try/catch block to that looks like this:

Function Do-Something {
[CmdletBinding()]
param()

            try {
## Ensure the thing exists. If not, this function will not continue
if (-not (Test-Path –Path 'C:\FileThatDoesNotExist.txt')) {
Write-Host 'The file does not exist'
}
Write-Host 'The file does exist'
} catch {

            }
}

Above I'm testing if something exists. In this case, it's a file. If not, the function needs to stop. At this point though when I run this I find that it's running both cases.

Figure 1.

The reason is that I just use an if statement. There's no else statement to accompany it. Rather than putting in an if/then/else statement, I need another way. This is where the throw command comes in.

The throw command is how exceptions are thrown to the catch block. Once an exception is thrown to the catch block, PowerShell will skip over everything else in the try block. Throw commands accept messages which typically indicate the error that occurred. In our example, I would like to let the user know that the file did not exist by throwing an exception to the catch blog. Our command might now look something like this:

Function Do-Something {
[CmdletBinding()]
param()

            try {
## Ensure the thing exists. If not, this function will not continue
if (-not (Test-Path –Path 'C:\FileThatDoesNotExist.txt')) {
throw 'The file does not exist'
}
Write-Host 'The file does exist'
} catch {

            }
}

I run it now and did not get a second message, but I didn't get anything at all!

Figure 2.

The reason was that the throw command did its job and skipped over the other Write-Host reference, but I had nothing in the catch block to something with the exception.

When an exception enters the catch block, it's always represented as the familiar pipeline variable $_. Here, I'll simply make a reference to that variable which will get output to the console.

Function Do-Something {
[CmdletBinding()]
param()

            try {
## Ensure the thing exists. If not, this function will not continue
if (-not (Test-Path –Path 'C:\FileThatDoesNotExist.txt')) {
throw 'The file does not exist'
}
Write-Host 'The file does exist'
} catch {
$_
}
}

[Click on image for larger view.] Figure 3.

You'll see the message that was thrown along with some familiar-looking error details although not in red. This is an error record and is commonly shown when errors occur in various PowerShell commands. Do you need to make this in the official red? No problem. Let's treat this exception as an actual error by sending it to the error stream with Write-Error.

Function Do-Something {
[CmdletBinding()]
param()

            try {
## Ensure the thing exists. If not, this function will not continue
if (-not (Test-Path –Path 'C:\FileThatDoesNotExist.txt')) {
throw 'The file does not exist'
}
Write-Host 'The file does exist'
} catch {
Write-Error $_
}
}

[Click on image for larger view.] Figure 4.

That's better. You can do anything you want with this error record object like parsing the message in different ways, displaying a warning instead of an error, etc.

A try/catch block is an excellent way to handle both errors that you anticipate by manually throwing the exception in code as well as exceptions that are thrown by other cmdlets. The catch block will catch any exception thrown inside of the try block regardless of where it originated from.

About the Author

Adam Bertram is a 20-year veteran of IT. He's an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam also founded the popular TechSnips e-learning platform. He mainly focuses on DevOps, system management and automation technologies, as well as various cloud platforms mostly in the Microsoft space. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion. Catch up on Adam's articles at adamtheautomator.com, connect on LinkedIn or follow him on Twitter at @adbertram or the TechSnips Twitter account @techsnips_io.


comments powered by Disqus
Most   Popular