Describes how to use the Try , Catch , and Finally blocks to handle terminating errors.
Use Try , Catch , and Finally blocks to respond to or handle terminating errors in scripts. The Trap statement can also be used to handle terminating errors in scripts. For more information, see about_Trap.
A terminating error stops a statement from running. If PowerShell does not handle a terminating error in some way, PowerShell also stops running the function or script using the current pipeline. In other languages, such as C#, terminating errors are referred to as exceptions.
Use the Try block to define a section of a script in which you want PowerShell to monitor for errors. When an error occurs within the Try block, the error is first saved to the $Error automatic variable. PowerShell then searches for a Catch block to handle the error. If the Try statement does not have a matching Catch block, PowerShell continues to search for an appropriate Catch block or Trap statement in the parent scopes. After a Catch block is completed or if no appropriate Catch block or Trap statement is found, the Finally block is run. If the error cannot be handled, the error is written to the error stream.
A Catch block can include commands for tracking the error or for recovering the expected flow of the script. A Catch block can specify which error types it catches. A Try statement can include multiple Catch blocks for different kinds of errors.
A Finally block can be used to free any resources that are no longer needed by your script.
Try , Catch , and Finally resemble the Try , Catch , and Finally keywords used in the C# programming language.
A Try statement contains a Try block, zero or more Catch blocks, and zero or one Finally block. A Try statement must have at least one Catch block or one Finally block.
The following shows the Try block syntax:
The Try keyword is followed by a statement list in braces. If a terminating error occurs while the statements in the statement list are being run, the script passes the error object from the Try block to an appropriate Catch block.
The following shows the Catch block syntax:
Error types appear in brackets. The outermost brackets indicate the element is optional.
The Catch keyword is followed by an optional list of error type specifications and a statement list. If a terminating error occurs in the Try block, PowerShell searches for an appropriate Catch block. If one is found, the statements in the Catch block are executed.
The Catch block can specify one or more error types. An error type is a Microsoft .NET Framework exception or an exception that is derived from a .NET Framework exception. A Catch block handles errors of the specified .NET Framework exception class or of any class that derives from the specified class.
If a Catch block specifies an error type, that Catch block handles that type of error. If a Catch block does not specify an error type, that Catch block handles any error encountered in the Try block. A Try statement can include multiple Catch blocks for the different specified error types.
The following shows the Finally block syntax:
The Finally keyword is followed by a statement list that runs every time the script is run, even if the Try statement ran without error or an error was caught in a Catch statement.
Note that pressing CTRL + C stops the pipeline. Objects that are sent to the pipeline will not be displayed as output. Therefore, if you include a statement to be displayed, such as "Finally block has run", it will not be displayed after you press CTRL + C , even if the Finally block ran.
The following sample script shows a Try block with a Catch block:
The Catch keyword must immediately follow the Try block or another Catch block.
PowerShell does not recognize "NonsenseString" as a cmdlet or other item. Running this script returns the following result:
When the script encounters "NonsenseString", it causes a terminating error. The Catch block handles the error by running the statement list inside the block.
USING MULTIPLE CATCH STATEMENTS
A Try statement can have any number of Catch blocks. For example, the following script has a Try block that downloads MyDoc.doc , and it contains two Catch blocks:
The first Catch block handles errors of the System.Net.WebException and System.IO.IOException types. The second Catch block does not specify an error type. The second Catch block handles any other terminating errors that occur.
PowerShell matches error types by inheritance. A Catch block handles errors of the specified .NET Framework exception class or of any class that derives from the specified class. The following example contains a Catch block that catches a "Command Not Found" error:
The specified error type, CommandNotFoundException, inherits from the System.SystemException type. The following example also catches a Command Not Found error:
This Catch block handles the "Command Not Found" error and other errors that inherit from the SystemException type.
If you specify an error class and one of its derived classes, place the Catch block for the derived class before the Catch block for the general class.
ACCESSING EXCEPTION INFORMATION
Within a Catch block, the current error can be accessed using $_ , which is also known as $PSItem . The object is of type ErrorRecord.
Running this script returns the following result:
There are additional properties that can be accessed, such as ScriptStackTrace, Exception, and ErrorDetails. For example, if we change the script to the following:
The result will be similar to:
FREEING RESOURCES BY USING FINALLY
To free resources used by a script, add a Finally block after the Try and Catch blocks. The Finally block statements run regardless of whether the Try block encounters a terminating error. PowerShell runs the Finally block before the script terminates or before the current block goes out of scope.
A Finally block runs even if you use CTRL + C to stop the script. A Finally block also runs if an Exit keyword stops the script from within a Catch block.
This throws the following exception:
How can I catch it entirely or at least filter out the "A resource with the same name already exist."?
Using $_.Exception.GetType().FullName yields
and $_.Exception.Message gives
The remote server returned an error: (400) Bad Request.
5 Answers 5
Errors and exceptions in PowerShell are structured objects. The error message you see printed on the console is actually a formatted message with information from several elements of the error/exception object. You can (re-)construct it yourself like this:
If you just want the error message displayed in your catch block you can simply echo the current object variable (which holds the error at that point):
If you need colored output use Write-Host with a formatted string as described above:
With that said, usually you don’t want to just display the error message as-is in an exception handler (otherwise the -ErrorAction Stop would be pointless). The structured error/exception objects provide you with additional information that you can use for better error control. For instance you have $_.Exception.HResult with the actual error number. $_.ScriptStackTrace and $_.Exception.StackTrace , so you can display stacktraces when debugging. $_.Exception.InnerException gives you access to nested exceptions that often contain additional information about the error (top level PowerShell errors can be somewhat generic). You can unroll these nested exceptions with something like this:
In your case the information you want to extract seems to be in $_.ErrorDetails.Message . It’s not quite clear to me if you have an object or a JSON string there, but you should be able to get information about the types and values of the members of $_.ErrorDetails by running
If $_.ErrorDetails.Message is an object you should be able to obtain the message string like this:
otherwise you need to convert the JSON string to an object first:
Depending what kind of error you’re handling, exceptions of particular types might also include more specific information about the problem at hand. In your case for instance you have a WebException which in addition to the error message ( $_.Exception.Message ) contains the actual response from the server:
which provides you with information like this:
Since not all exceptions have the exact same set of properties you may want to use specific handlers for particular exceptions:
If you have operations that need to be done regardless of whether an error occured or not (cleanup tasks like closing a socket or a database connection) you can put them in a finally block after the exception handling:
One of the key parts of any good PowerShell script is error handling. Even in the shortest script, being able to handle errors helps to ensure that an unexpected event will not go on to wreck the system you are working on. Take the example below. Every week in our sample company (MyCompany.Com) Human Resources are going to upload a list telling us who should have access to the Expenses database. If a name isn’t in the list from HR we’re going to remove it from the group and that user will no longer be able to log expense claims:
Now, you can see where this is going to go wrong. One week HR doesn’t get around to uploading the list or, just as we are about to access the list, the file server dies. Suddenly PowerShell throws an error on the Get-Content cmdlet and the $AuthorizedUser variable remains empty. Because our script doesn’t handle errors, it continues to run and, in a very short space of time, it has removed every user from our expenses group. Pretty soon the irate phone calls start flooding in and life gets a little less happy. The way to avoid all this is to catch the errors and then handle the event that caused them (which in this case is halt the script and have a shout at someone in HR).
Terminating and Non-Terminating Errors
One of the key things to know when catching errors is that only certain errors can be caught by default. Errors come in two types – terminating and non-terminating. A terminating error is an error that will halt a function or operation. If you make a syntax error or run out of memory, that is a terminating error. Terminating errors can be caught and handled. Non-terminating errors allow Powershell to continue and usually come from cmdlets or other managed situations. Under normal circumstances they cannot be caught by Try-Catch-Finally. The Get-Content error in the example above is a non-terminating error.
Treating Non-Terminating Errors as Terminating
So how do you catch a Non-Terminating error? Basically, you tell PowerShell to treat it as terminating. To do this you use the ErrorAction parameter. Every PowerShell cmdlet supports ErrorAction. By specifying -ErrorAction Stop on the end of a cmdlet you ensure that any errors it throws are treated as terminating and can be caught. In our example above we are going to change our Get-Content line to:
Treating All Errors as Terminating
It is also possible to treat all errors as terminating using the ErrorActionPreference variable. You can do this either for the script your are working with or for the whole PowerShell session. To set it in a script, make the first line $ErrorActionPreference = Stop. To set it for the session, type $ErrorActionPreference = Stop at the PowerShell console.
Catching a Terminating Error
Once you have ensured that the error you are trying to catch is going to be treated as terminating, you can build a Try Catch block around the command (or commands) that might cause the error. The first stage is to surround the section of your script that may throw the error with a Try block. In our example the Get-Content line becomes:
Immediately after the Try block you must place a Catch block to deal with the error. The Catch block is only accessed if a terminating error occurs, otherwise it is ignored. In our example we are going to email an admin to say that there has been an error and then halt the script. Our Get-Content line is now:
Accessing The Error Record
Once you are inside a catch block you can access the error record, which is stored in the current object variable, $_. Error records have various useful properties, but the main one you will want to access is $_.Exception. Exceptions are what we are really dealing with here as we catch and deal with errors – exceptions are the unexpected event that caused the error (the error record itself is actually only really a wrapper for presenting the exception to the PowerShell user). It is the exception that we are catching and the exception that contains all the really useful information about the problem. If there was a further underlying problem that caused our exception, it is also recorded at $_.exception.innerexception (and so on – the next underlying exception is stored at $_.exception.innerexception.innerexception etc.). For the purposes of our example we are going to use $_.Exception to put some extra information into our notification email, using the $_.Exception.Message and $_.Exception.ItemName properties:
Catching Specific Exceptions
Now, as our example stands we are catching any errors that occur during the file read and dealing with all of them in the same way. You can however catch specific exceptions and deal with them differently, but – and it’s a big but – only if the original error is terminating. Because the Get-Content cmdlet throws non-terminating errors (that we have only treated as terminating using ErrorAction) we cannot specifically catch the different exceptions that the cmdlet might throw. This is a feature of PowerShell and applies to any non-terminating error, regardless of the ErrorActionPreference and cannot be changed. Still, we can deal with other terminating exceptions, such as an out of memory error, that could crop up during the read operation. For the purposes of this example that is what we will do.
You catch specific terminating errors by specifying the exception name immediately after the Catch keyword. In our example we want to catch a System.OutOfMemory exception and, if we get one, will take the no nonsense approach of rebooting the computer immediately. We will also include a general catch block after our file not found block to catch all other exceptions:
Finally, Using Finally
The last part of Try Catch Finally is the Finally block. This must be defined immediately after the Catch block and runs every time, regardless of whether there was an error or not. In this way you can perform actions that need to be made regardless of whether an operation succeeds or fails. In our example we are going to log that a file read was attempted. Our Get-Content line now looks like: