As $error is a global variable, consider using your own logging variable for error handling so you don't affect other users (and vice versa).
Error handling without interrupting cmdlets
Whenever PowerShell encounters an unhandled exception, it is stored in the global $error variable. This can be used for error handling. Here is typical code:
# clear error log
$error.Clear()
# hide error messages from the user
$ErrorActionPreference = 'SilentlyContinue'
# perform cmdlet actions, i.e. find log files
$result = Get-ChildItem -Path $env:windir -Depth 1 -Filter *.log
# perform more actions, i.e. access a service that does not exist
$service = Get-Service -Name notThere
# restore default error action
$ErrorActionPreference = 'Continue'
# check errors after the fact
$errorCount = $error.Count
Write-Host "There were $errorCount errors."
# output error details
$error.CategoryInfo | Select-Object -Property Category, TargetName
This type of error handling is generally perfect when you want cmdlets to first complete their work, and not aborting them.
However, $error is a global variable, so when you clear it, you may be affecting other users. Likewise, your own error logging may be affected by commands you use from 3rd party modules (as they may clear this variable, too, at any time).
Thats why it is safer to use your own error logging variable. Note how the code below is not touching $error at all:
# perform cmdlet actions, i.e. find log files
$result = Get-ChildItem -Path $env:windir -Depth 1 -Filter *.log -ErrorAction SilentlyContinue -ErrorVariable myErrors
# perform more actions, i.e. access a service that does not exist
$service = Get-Service -Name notThere -ErrorAction SilentlyContinue -ErrorVariable +myErrors
# check errors after the fact
$errorCount = $myErrors.Count
Write-Host "There were $errorCount errors."
# output error details
$myErrors.CategoryInfo | Select-Object -Property Category, TargetName
Instead, the ?ErrorVariable parameter specifies the name of your own variable that youd like to use for error logging, in this case "myErrors". This instructs the cmdlet to generate the new variable $myErrors. If you append the variable name by "+", the cmdlet uses an existing variable so you can log the errors of more than one cmdlet in this variable.
If youd like to log all errors of all cmdlets in your script like this, you may want to change $ErrorActionPreference to "SilentlyContinue", and use $PSDefaultParameterValues to always use ?ErrorVariable on all of your cmdlets:
# clear error variable if it exists from a previous run
$variableExists = Get-Variable -Name myErrors -Scope 0 -ErrorAction Ignore
if ($variableExists) { Remove-Variable -Name myErrors }
# add private error logging to all cmdlets
$ErrorActionPreference = 'SilentlyContinue'
$PSDefaultParameterValues.Add('*:ErrorVariable', '+myErrors')
# perform cmdlet actions, i.e. find log files
$result = Get-ChildItem -Path $env:windir -Depth 1 -Filter *.log
# perform more actions, i.e. access a service that does not exist
$service = Get-Service -Name notThere
# check errors after the fact
$errorCount = $myErrors.Count
Write-Host "There were $errorCount errors."
# output error details
$myErrors.CategoryInfo | Select-Object -Property Category, TargetName
Your ultimate PowerShell Cheat Sheet
Unleash the full potential of PowerShell with our handy poster. Whether you're a beginner or a seasoned pro, this cheat sheet is designed to be your go-to resource for the most important and commonly used cmdlets.The poster is available for download and in paper form.
Related links
- ScriptRunner ActionPacks will help you automate tasks
- Try out ScriptRunner here
- ScriptRunner: Book a demo with our product experts