Exceptions and Error Handling (PowerShell)
Behaviour on Exception
To control how a script behaves as a result of an exception, modify the $ErrorActionPreference
variable, if required.
In the default continue mode, an error will output to the screen, then the script will continue. By outputting the error to the screen PowerShell CmdLets consider the exception to have been handled! If you want the opportunity to catch
or trap
you may need to append -ErrorAction:Stop
to the CmdLet you expect might fail. However this doesn't appear to be consistent, and some trial and error is to be expected.
Value | Effect |
---|---|
Continue | [Default] Outputs error, but keeps processing |
SilentlyContinue | No output and it keeps going |
Inquire | Prompt user for action |
Stop | Outputs error and halts processing |
$error
Provides a list of recent errors experienced - which can be invaluable for properly identifying and investigating errors. The object is the same as found in a pipeline when an exception has occurred.
Property | Description | Example (VC login error) |
---|---|---|
$error[1].Exception.GetType().FullName |
Error class for specific error | [VMware.VimAutomation.ViCore.Types.V1.ErrorHandling.InvalidLogin]
|
$error[1].Exception.Message |
User friendly error message | 16/11/2010 10:32:52 Connect-VIServer Login failed due to a bad username or password.
|
$error[1].ErrorDetails.Message |
Shorter friendly error message | Login failed due to a bad username or password
|
$error[1].CategoryInfo.Reason |
Short error message | InvalidLogin
|
$error[1].InvocationInfo |
Invocation info (what triggered exception) | Various info including script command |
Basic Error Handler
If you know where the error is likely to occur, then just place an error catcher immediately after it. This doesn't stop the exception appearing on the console, but does allow you to take some action as a result.
if (-not $?) {
# Handle error here
}
Try...Catch
Used to catch an exception in a script block where an exception may be likely. Stops the exception being shown on the console and gives you a chance to do something about it (as long as you've set $ErrorActionPreference
to Stop or used -ErrorAction:Stop
).
try
{
# Something in which an exception is likely
}
catch
{
Write-Host "FAILED: $_"
Exit
}
The error returned by the CmdLet can be found in $_
, so this can be tested to ensure the error is as expected (just because you though a command might fail, doesn't mean it failed in the way you expected). For example, $_
will contain the bold bit of the following error.
Get-Log : Cannot validate argument on parameter 'StartLineNum'. The 0 argument is less than the minimum allowed range of 1. Supply an argument that is greater than 1 and then try the command again. At C:\Users\simonstrutt\Documents\Scripts\ESX-LogTail.ps1:20 char:57 + $ESXLog = Get-Log $logKey -VMHost $ESX -StartLineNum <<<< $LineNo + CategoryInfo : InvalidData: (:) [Get-Log], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.Commands.GetLog
This can be elaborated on to make the catch handling more specific, by making the catch block executed depend on the error class. The error class can be determined by making causing the error to be thrown, in which case the class can be found at $_.Exception.GetType().FullName
.
try {
$proxy = New-WebServiceProxy -uri $endpoint -cred $credential -ErrorAction:Stop
} catch [System.Net.WebException] {
Write-Host "ERROR: Unable to connect to SOAP server"
Write-Host $_
} catch {
Write-Host "ERROR: Unexpected error"
Write-Host $_
Write-Host $_.Exception.Message
Write-Host $_.Exception.GetType().FullName
}
Trap
Used to capture any unhanded exception that occurs anywhere. I tend to consider this a last resort catch-all, though really it depends on the nature of your script. For example if your script is reliant on a connection to a server that can go down, you can design a trap to recover from that specific occurrence rather than having to put a Try...Catch around every operation that could fail.
The key to an effective trap
is allowing for the fact that anything might go wrong, therefore you have to set your traps up to handle only specific cases and in all likelihood stop on anything else.
trap {
# Handle the exception
Continue
}
Sources / Further Reading
- Exception trapping
- Error handling