Skip to main content

Using try/catch/finally Blocks in PowerShell

Despite being a great language, PowerShell is not impervious to errors. Errors that occur within your code can stop it’s execution or even cause unexpected changes in the resources that your script is managing. Learning to handle these errors gracefully is the foundation of defensive coding. Today, we’ll take a quick look at how PowerShell handles errors with Try-Catch-Finally blocks. They allow you to gracefully handle errors and perform cleanup operations, ensuring that your script doesn’t crash when the unexpected occurs. We’ll then cover the differences in terminating and non-terminating errors and why you should take these into consideration when implementing error handling.

The Try Block

The Try block is where you place the code that might generate an error. Think of it as a protective bubble around your potentially troublesome code. If an error occurs within the Try block, PowerShell will immediately jump to the corresponding Catch block.

Here’s a simple example:

try {
    # Code that might generate an error
    Get-Item -Path "NonexistentFile.txt"
}
catch {
    # Code to handle the error
    Write-Host "An error occurred: $_"
}

The Catch Block

The Catch block is where you can handle the error. PowerShell provides you with a special variable $_ that contains information about the error. You can use this variable to display error messages or even take corrective actions.

In the example above, we’re capturing the error generated by attempting to retrieve a nonexistent file. The $_ variable holds the error message, which we’re displaying using Write-Host.

The Finally Block

Now, let’s talk about the unsung hero – the Finally block. This block is executed regardless of whether an error occurred or not. It’s where you can place cleanup code that ensures your script leaves no trace behind, even in the face of adversity. Some tasks that are commonly done in the finally block are closing database connections, removing temp files, etc. The finally block is completely optional.


try {
    # Code that might generate an error
    # ...
}
catch {
    # Code to handle the error
    # ...
}
finally {
    # Cleanup code here
    # ...
}

Terminating/non-terminating Errors

non-terminating errors are any error that will not stop the execution of your script. Most cmdlets in PowerShell are non-terminating. They may output an error, but your script will continue to run. These kinds of errors cannot be caught with a catch block by default. The reason for this is the default ErrorAction in your PowerShell profile, which is set to Continue.

# To show your default error action type
$ErrorActionPreference

Let’s go back and look at our first example:

try {
    # Code that might generate an error
    Get-Item -Path "NonexistentFile.txt"
}
catch {
    # Code to handle the error
    Write-Host "An error occurred: $_"
}

If you took the time to run this code, you may have noticed that the Write-Host cmdlet in the catch block was never ran. Why did we get a red error message in our PowerShell console, rather than the text An error occurred: ...? The reason is that the non-existing path isn’t a terminating error, and the default ErrorAction is Continue. To catch the error, you will need to change the ErrorAction in your PowerShell console to Stop. This can be done in multiple ways. You can add -ErrorAction Stop to the cmdlet, like this:

try {
    # Code that might generate an error
    Get-Item -Path "NonexistentFile.txt" -ErrorAction Stop
}
catch {
    # Code to handle the error
    Write-Host "An error occurred: $_"
}

Or you can change the ErrorActionPreference for the entire script, by adding this to the top of the script:

$ErrorActionPreference = "Stop"

Exceptions

If you have ever worked with exceptions in C# you can skip this section. In the previous examples, we used simple catch blocks that will catch any error. This is a good start, but we can do better. PowerShell allows you to catch individual exceptions based on the exception type, similar to how C# handles catching exceptions.

Let’s look at an example:

try {
    # Attempt to open a non-existent file
    $file = Get-Content -Path "NonexistentFile.txt"
}
catch [System.IO.FileNotFoundException] {
    Write-Host "Caught a FileNotFoundException: $_"
}
catch {
    Write-Host "Caught an exception: $_"
}

We now have two catch blocks. If we encounter an exception of type System.IO.FileNotFoundException, the first catch block will catch the exception and handle it accordingly. The second catch block will handle any other generic error.

Conclusion

Error handling might seem daunting at first, but with the power of Try-Catch-Finally blocks at your fingertips, you’re well-equipped to handle errors gracefully and ensure the resilience of your PowerShell scripts. Remember, every error is an opportunity to refine your skills and make your scripts more robust.

Thanks for reading!

Official Microsoft Documentation for Try-Catch-Finally in PowerShell: about_try_catch_finally