When trapping an error, try to use -ErrorAction Stop on cmdlets to generate terminating, trappable exceptions.
When executing something other than a cmdlet, set $ErrorActionPreference = 'Stop' before executing, and re-set to Continue afterwards. If you're concerned about using -ErrorAction because it will bail on the entire pipeline, then you've probably over-constructed the pipeline. Consider using a more scripting-construct-style approach, because those approaches are inherently better for automated error handling.
Ideally, whatever command or code you think might bomb should be dealing with one thing: querying one computer, deleting one file, updating one user. That way, if an error occurs, you can handle it and then get on with the next thing.
Try to avoid setting flags:
try {
$continue = $true
Do-Something -ErrorAction Stop
} catch {
$continue = $false
}
if ($continue) {
Do-This
Set-That
Get-Those
}
Instead, put the entire "transaction" into the Try block:
try {
Do-Something -ErrorAction Stop
Do-This
Set-That
Get-Those
} catch {
Handle-Error
}
It's a lot easier to follow the logic.
When you need to examine the error that occurred, try to avoid using $?. It actually doesn't mean an error did or did not occur; it's reporting whether or not the last-run command considered itself to have completed successfully. You get no details on what happened.
Also try to avoid testing for a null variable as an error condition:
$user = Get-ADUser -Identity DonJ
if ($user) {
$user | Do-Something
} else {
Write-Warning "Could not get user $user"
}
There are times and technologies where that's the only approach that will work, especially if the command you're running won't produce a terminating, trappable exception. But it's a logically contorted approach, and it can make debugging trickier.
Within a catch
block, $_
will contain the last error that occurred, as will $Error[0]
. Use either - but immediately copy them into your own variable, as executing additional commands can cause $_
to get "hijacked" or $Error[0]
to contain a different error.
It isn't necessary to clear $Error
in most cases. $Error[0]
will be the last error, and PowerShell will maintain the rest of the $Error
collection automatically.