A girl is a programmer
Fix Joseph Posted on 5:27 am

Mastering Error Handling: A Comprehensive Guide

Error handling in PowerShell might seem like an extra step in script development, but it can save you valuable time in the long run. Consider a scenario where your script processes user data from a database or file, updates Active Directory information, and disables accounts. Everything runs smoothly until the database server crashes, leaving your $userAccounts variable empty. Without error handling, your script might inadvertently delete all user accounts. While this is an extreme example, similar situations can occur, making error handling a crucial aspect of script writing.

Understanding PowerShell Errors

In PowerShell, errors are stored in the automatic variable $error. To get a count of errors encountered in your session, use $error.count. These errors are essentially an array, and you can access the first error with $error[0]. To delve deeper into the first error, you can use $error[0] | Get-Member. Here, we can inspect the command that caused the error via $error[0].InvocationInfo. The Line property within InvocationInfo contains the full command that triggered the error.

To access the exception that caused the error, you can use $error[0].Exception. Further details about the exception are available through $error[0].Exception | Get-Member. This information includes the TypeName, which becomes useful when handling specific errors. To obtain the exception’s message in string format, use $error[0].Exception.Message.

Types of Errors in PowerShell

Terminating Errors

Terminating errors indicate that the script cannot proceed due to encountered issues. Without error handling, these errors are displayed in the familiar red text, effectively halting the script’s execution. Terminating errors terminates pipeline output, except for the error message.

An example of a terminating error occurs when calling a non-existent command:

Get-TerminatingError

Non-Terminating Errors

In contrast, non-terminating errors do not stop the pipeline’s execution. PowerShell’s internal handling manages these errors, making them inaccessible for error handling. However, there are ways to force non-terminating errors to become terminating, allowing for error capture.

For instance, consider a non-terminating error like access denied to a subfolder when listing all folders and subfolders in “C:\Windows\appcompat”:

Get-ChildItem -Path ‘C:\Windows\appcompat’ -Recurse

Forcing Non-Terminating Errors to Terminate

There are methods to compel non-terminating errors to become terminating errors, enabling custom error handling. This feature is not always required, but can be handy when needed.

$ErrorActionPreference

At the session level, you can control non-terminating errors’ behavior using the $ErrorActionPreference variable, which offers various values:

  • Stop: Display the error and halt execution;
  • Inquire: Display the error and prompt to continue;
  • Continue (Default): Display the error and continue execution;
  • Suspend: Designed for workflows, suspends the job for investigation;
  • Silently Continue: Suppresses error display and continues execution.

For example:

Get-ChildItem -Path ‘C:\Windows\appcompat’ -Recurse; Write-Host ‘Test’

With non-terminating errors, the subsequent command is executed, resulting in ‘Test’ output. However, setting $ErrorActionPreference to ‘Stop’ transforms the non-terminating error into a terminating one:

$ErrorActionPreference = ‘Stop’Get-ChildItem -Path ‘C:\Windows\appcompat’ -Recurse; Write-Host ‘Test’

Now, the next command doesn’t execute, showcasing the effectiveness of error handling.

Command’s -ErrorAction Parameter

Cmdlets, functions, scripts, and modules using [cmdletbinding()] enable the use of the -ErrorAction common parameter. This parameter allows you to specify actions when an error occurs, including:

  • Stop: Display the error and halt execution;
  • Inquire: Display the error and prompt to continue;
  • Continue (Default): Display the error and continue execution;
  • Suspend: Designed for workflows, suspends the job for investigation;
  • SilentlyContinue: Suppresses error display and continues execution;
  • Ignore: Similar to SilentlyContinue, but doesn’t add the message to the $error automatic variable.

Implementing Error Handling Strategies

Validation

The most straightforward method for handling errors is validation through conditional statements, like the if statement. Validation helps prevent errors before they occur.

if (Get-ChildItem Z:\ -ErrorAction SilentlyContinue) {    Write-Host ‘I can list the contents of Z!’} else {    Write-Host ‘I cannot list the contents of Z!’}

In this example, the -ErrorAction common parameter with the value SilentlyContinue suppresses the error display, allowing the if statement to perform validation.

You can also use variables with if statements to check for emptiness:

$myVariable = $null
if ($myVariable) {    Write-Host “We have information! Let’s do stuff.”} else {    Write-Host “`$myVariable is empty :(“}

Try/Catch/Finally Blocks

Try, Catch, and Finally, blocks are essential for managing terminating errors effectively. They provide structured error handling:

  • Try Block: Contains the code to execute;
  • Catch Block: Handles exceptions and executes specific code when an error occurs. The current error is accessible through $_;
  • Finally Block: Contains cleanup tasks and runs after the error event (optional).
Try {    $command = ‘Invoke-FakeCommand’    Write-Host “Attempting to run: [Invoke-Expression -Command $command]”`n    Invoke-Expression -Command $command}Catch {    Write-Host $_.Exception.Message`n}Finally {    Write-Host “Clean up: `$command = `$null”`n    $command = $null}

The Try block executes the code, the Catch block handles the exception, and the Finally block performs cleanup.

Catch Specific Errors

To handle specific exceptions, specify the exception type in the Catch block. This allows you to customize error handling for different scenarios.

Try {    Get-ThisWontWork}Catch [System.Management.Automation.CommandNotFoundException] {    Write-Host “Command not found!”`n -ForegroundColor Red     Write-Host “Message: [$($_.Exception.Message)”] -ForegroundColor Red -BackgroundColor DarkBlue}

In this example, a System.Management.Automation.CommandNotFoundException is caught, and specific actions are taken.

Get Detailed Error Information

Obtaining detailed error information is crucial for creating specific Catch blocks. A custom function can simplify this process:

function Get-ErrorInformation {    [cmdletbinding()]    param($incomingError)
    if ($incomingError -and (($incomingError| Get-Member | Select-Object -ExpandProperty TypeName -Unique) -eq ‘System.Management.Automation.ErrorRecord’)) {
        Write-Host `n” Error information:”`n        Write-Host `t”Exception type for catch: [$($IncomingError.Exception | Get-Member | Select-Object -ExpandProperty TypeName -Unique)]”`n 
        if ($incomingError.InvocationInfo.Line) {            Write-Host `t”Command: [$($incomingError.InvocationInfo.Line.Trim())]”`        } else {            Write-Host `t”Unable to get command information! Multiple catch blocks can do this :(“`n        }
        Write-Host `t”Exception: [$($incomingError.Exception.Message)]”`n        Write-Host `t”Target Object: [$($incomingError.TargetObject)]”`n        }    Else {        Write-Host “Please include a valid error record when using this function!” -ForegroundColor Red -BackgroundColor DarkBlue    }}

With this function, you can simplify error handling and create specific Catch blocks. Use it like this:

Try {    Get-ChildItem -Path Z:\ -ErrorAction Stop    Get-ThisWontWork}Catch [System.Management.Automation.CommandNotFoundException] {    Write-Host ‘Command not found Catch block executed!’ }Catch [System.Management.Automation.DriveNotFoundException] {    Write-Host ‘Get-ChildItem drive not found Catch block executed!’}Catch {   Get-ErrorInformation -incomingError $_}

This allows you to capture specific error information effectively.

Video Guide

To finally answer all your questions, we have prepared a special video for you. Enjoy watching it!

Conclusion

Handling errors in PowerShell is essential for creating robust and reliable scripts. Understanding the types of errors, forcing non-terminating errors to terminate, and implementing error handling techniques like validation and Try/Catch/Finally blocks can save you time and prevent unexpected issues. By mastering error handling, you ensure that your automation tasks run smoothly and securely, even in challenging scenarios.