Error Handling
Methods for handling errors in PowerShell can range from simple to complex. The simple method is to allow PowerShell to handle the error. Depending on the type of error, the command or script might terminate or continue. However, if the default error handler doesn't fit your needs, you can devise a more complex error-handling scheme by using the methods discussed in the following sections.
Method One: cmdlet Preferences
In PowerShell, ubiquitous parameters are available to all cmdlets. Among them are the ErrorAction and ErrorVariable parameters, used to determine how cmdlets handle nonterminating errors, as shown in this example:
PS C:\> get-childitem z: -ErrorVariable Err -ErrorAction SilentlyContinue PS C:\> if ($Err){write-host $Err -Foregroundcolor Red} Cannot find drive. A drive with name 'z' does not exist. PS C:\> |
The ErrorAction parameter defines how a cmdlet behaves when it encounters a nonterminating error. In the preceding example, ErrorAction is defined as SilentlyContinue, meaning the cmdlet continues running with no output if it encounters a nonterminating error. Other options for ErrorAction are as follows:
- Continue—Print error and continue (default action)
- Inquire—Ask users whether they want to continue, halt, or suspend
- Stop—Halt execution of the command or script
The ErrorVariable parameter defines the variable name for the error object generated by a nonterminating error. As shown in the previous example, ErrorVariable is defined as Err. Notice the variable name doesn't have the $ prefix. However, to access ErrorVariable outside a cmdlet, you use the variable's name with the $ prefix ($Err). Furthermore, after defining ErrorVariable, the resulting variable is valid for the current PowerShell session or associated script block. This means other cmdlets can append error objects to an existing ErrorVariable by using a + prefix, as shown in this example:
PS C:\> get-childitem z: -ErrorVariable Err -ErrorAction SilentlyContinue PS C:\> get-childitem y: -ErrorVariable +Err -ErrorAction SilentlyContinue PS C:\> write-host $Err[0] -Foregroundcolor Red Cannot find drive. A drive with name 'z' does not exist. PS C:\> write-host $Err[1] -Foregroundcolor Red Cannot find drive. A drive with name 'y' does not exist. PS C:\> |
Method Two: Trapping Errors
When encountering a terminating error, PowerShell's default behavior is to display the error and halt the command or script execution. If you want to use custom error handling for a terminating error, you must define an exception trap handler to prevent the terminating error (ErrorRecord) from being sent to the default error-handling mechanism. The same holds true for nonterminating errors as PowerShell's default behavior is to just display the error and continue the command or script execution.
To define a trap, you use the following syntax:
trap ExceptionType {code; keyword} |
The first part is ExceptionType , which specifies the type of error a trap accepts. If no ExceptionType is defined, a trap accepts all errors. The code part can consist of a command or set of commands that run after an error is delivered to the trap. Defining commands to run by a trap is optional. The last part, keyword , is what determines whether the trap allows the statement block where the error occurred to execute or terminate.
Supported keywords are as follows:
- Break—Causes the exception to be rethrown and stops the current scope from executing
- Continue—Allows the current scope execution to continue at the next line where the exception occurred
- Return [argument]—Stops the current scope from executing and returns the argument, if specified
If a keyword isn't specified, the trap uses the keyword Return [argument]; argument is the ErrorRecord that was originally delivered to the trap.
Trap Examples
The following two examples show how traps can be defined to handle errors. The first trap example shows a trap being used in conjunction with a nonterminating error that is produced from an invalid DNS name being given to the System.Net.Dns class. The second example shows a trap being again used in conjunction with a nonterminating error that is produced from the Get-Item cmdlet. However, in this case, because the ErrorAction parameter has been defined as Stop, the error is in fact a terminating error that is then handled by the trap.
Example one: errortraps1.ps1
$DNSName = "www.-baddnsname-.com" trap [System.Management.Automation.MethodInvocationException]{ write-host ("ERROR: " + $_) -Foregroundcolor Red; Continue} write-host "Getting IP address for" $DNSName write-host ([System.Net.Dns]::GetHostAddresses("www.$baddnsname$.com")) write-host "Done Getting IP Address" |
The $_ parameter in this example represents the ErrorRecord that was delivered to the trap.
Output:
PS C:\> .\errortraps1.ps1 Getting IP address for www.-baddnsname-.com ERROR: Exception calling "GetHostAddresses" with "1" argument(s): "No such host is known" Done Getting IP Address PS C:\> |
Example two: errortraps2.ps1
write-host "Changing drive to z:" trap {write-host("[ERROR] " + $_) -Foregroundcolor Red; Continue} get-item z: -ErrorAction Stop $TXTFiles = get-childitem *.txt -ErrorAction Stop write-host "Done getting items" |
Output:
PS C:\> .\errortraps2.ps1 Changing drive to z: [ERROR] Command execution stopped because the shell variable "ErrorActionPreference" is set to Stop: Cannot find drive. A drive with name 'z' does not exist. Done getting items PS C:\> |
Trap Scopes
A PowerShell scope, as discussed in Chapter 2, "PowerShell Basics," determines how traps are executed. Generally, a trap is defined and executed within the same scope. For example, you define a trap in a certain scope; when a terminating error is encountered in that scope, the trap is executed. If the current scope doesn't contain a trap and an outer scope does, any terminating errors encountered break out of the current scope and are delivered to the trap in the outer scope.
Method Three: The Throw Keyword
In PowerShell, you can generate your own terminating errors. This doesn't mean causing errors by using incorrect syntax. Instead, you can generate a terminating error on purpose by using the throw keyword, as shown in the next example if a user doesn't define the argument for the MyParam parameter when trying to run the MyParam.ps1 script. This type of behavior is very useful when data from functions, cmdlets, data sources, applications, etc. is not what is expected and hence may prevent the script or set of commands from executing correctly further into the execution process.
Script:
param([string]$MyParam = $(throw write-host "You did not define MyParam" -Foregroundcolor Red)) write-host $MyParam |
Output:
PS C:\ .\MyParam.ps1 You did not define MyParam ScriptHalted At C:\MyParam.ps1:1 char:33 + param([string]$MyParam = $(throw <<<< write-host "You did not define MyParam " -Foregroundcolor Red)) PS C:\> |