Error Handling

try~catch~finally / Automatic variables $? and $ErrorActionPreference / trap / throw

try~catch~finally statement

Error handling is possible with try~catch~finally statements.

Syntax

try {
    <statement list>
}
catch [[<error type>][',' <error type>]*] {
    <statement list>
}
finally {
    <statement list>
}

Sample Script

script.ps1

try {
    Write-Host 'try'
    aaa
}
catch {
    Write-Host 'catch'
    Write-Host $_
}
finally {
    Write-Host 'finally'
}

Execution example

PS C:\Users\user\Desktop> .\script.ps1
try
catch
用語 'aaa' コマンドレット関数スクリプト ファイルまたは操作可能なプログラ
ムの名前として認識されません名前が正しく記述されていることを確認しパスが含まれ 
ている場合はそのパスが正しいことを確認してから再試行してください
finally

How to access error information

For the details of the error and the location of the error,
You can check it with $_, $PSItem, $_.ScriptStackTrace, etc.

Script and example

script

script.ps1

$ErrorActionPreference = "Stop"
try {
    Write-Host "Main:try"
    Get-Content no_exist.txt # Open a non-existent file
}
catch {
    Write-Host "Main:catch"

    Write-Host '$_:' $_
    Write-Host '$PSItem:' $PSItem

    Write-Host '$_.ScriptStackTrace:'
    Write-Host $_.ScriptStackTrace
}

Execution example

PS /Users/user/Desktop> ./script.ps1
Main:try
Main:catch
$_: Cannot find path '/Users/user/Desktop/no_exist.txt' because it does not exist.
$PSItem: Cannot find path '/Users/user/Desktop/no_exist.txt' because it does not exist.
$_.ScriptStackTrace:
at <ScriptBlock>, /Users/user/Desktop/script.ps1: line 4
at <ScriptBlock>, <No file>: line 1

Specify the error control of the cmdlet

By setting a value to $ErrorActionPreference, you can specify the behavior when an error occurs.
PowerShell has errors that terminate and errors that do not terminate, as shown in the table below.

Value Behavior
Continue Display an error and continue. Default value
SilentlyContinue Continue without displaying an error
Ignore Similar to SilentlyContinue. However, it does not add the error content to the $error array.
Inquire Show confirmation prompt to user
Stop Stop the process when an error occurs

Errors that terminate will be caught.
On the other hand, Continue and SilentlyContinue will not be caught.

In the above Sample Script
In the first line, $ErrorActionPreference is set to Stop so that errors can be caught.

Specify the error control for the target cmdlet by -ErrorAction.

Use “-ErrorAction” if you want to control errors in the target cmdlet instead of the entire cmdlet.
It can also be abbreviated to “-ea”.

Example

PS C:\Users\user\Desktop> cat no_exist.txt
cat : Cannot find path 'C:\Users\user\Desktop\no_exist.txt' because it does not exist.
At line:1 char:1
+ cat no_exist.txt
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\user\Desktop\no_exist.txt:String) [Get-Content], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
 
PS C:\Users\user\Desktop> cat no_exist.txt -ErrorAction SilentlyContinue
PS C:\Users\user\Desktop>
PS C:\Users\user\Desktop> cat no_exist.txt -ea SilentlyContinue
PS C:\Users\user\Desktop>

trap statement

This has been available since PowerShell V1.

Since the try~catch~finally statement was added in PowerShell V2
You may not have many chances to use trap statement.

Syntax

trap [[<error type>]] {
    <statement list>
}

You can specify the behavior by adding break or continue in the trap statement.

  • Neither: Display an error and continue processing.
  • break: Display an error and terminate processing.
  • continue: Do not display an error and continue processing.

When there is no break or continue

Script
Write-Host "Pre"
no_exist_command
Write-Host "Post"
 
trap {
    Write-Host "Trap"
}
Execution example

Display an error and continue processing.

PS C:\Users\user\Desktop> .\script.ps1
Pre
Trap
no_exist_command : The term 'no_exist_command' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the n
ame, or if a path was included, verify that the path is correct and try again.
At C:\Users\user\Desktop\script.ps1:2 char:1
+ no_exist_command
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (no_exist_command:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
 
Post

When there is break

Script
Write-Host "Pre"
no_exist_command
Write-Host "Post"
 
trap {
    Write-Host "Trap"
    break # Changed
}
Execution example

Display an error and terminate processing.

PS C:\Users\user\Desktop> .\script.ps1
Pre
Trap
The term 'no_exist_command' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\Users\user\Desktop\script.ps1:2 char:1
+ no_exist_command
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (no_exist_command:String) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : CommandNotFoundException

When there is continue

Script
Write-Host "Pre"
no_exist_command
Write-Host "Post"
 
trap {
    Write-Host "Trap"
    continue # Changed
}
Execution example

Continue processing without displaying an error.

PS C:\Users\user\Desktop> .\script.ps1
Pre
Trap
Post

throw : To throw an error

Throw an error

PS> throw "Error!" # Display an error message
Error!
At line:1 char:1
PS> throw New-Object System.NullReferenceException # Raises the specified error
オブジェクト参照がオブジェクト インスタンスに設定されていません
At line:1 char:1

Re-throw error

If you throw in a catch in a lower level function,
you can pass the error to the catch of the upper level function.

function Sub {
    try {
        Write-Host "Sub :try"
        throw (Get-Date).ToString("yyyy/MM")    # First throw
    }
    catch {
        Write-Host "Sub :catch"
        throw    # Re-throw
    }
}
 
function Main {
    try {
        Write-Host "Main:try"
        Sub
    }
    catch {
        Write-Host "Main:catch"
        Write-Host $_    # Output the received error.
    }
    finally {
        Write-Host "Main:finally"
    }
}
 
Main
PS C:\Users\user\Desktop> .\script.ps1
Main:try
Sub :try  
Sub :catch
Main:catch
2020/11   
Main:finally
  • For rethrow, throw is recommended.
  • If you use throw "Error Message" when rethrowing, the number of errors ($error.Count) will be increased by one extra, so you may not want to do that.

stackoverflow How can I Rethrow an exception from catch block in Powershell?

Automatic variables for error handling

In this section, we will look at the following three automatic variables.

  • $?
  • $LastExitCode
  • $Error

$? and $LastExitCode

Automatic variables about errors are $? and $LastExitCode.

The two automatic variables store different information.
$? stores True if the result of the last operation was successful, False if it failed.
$LastExitCode stores the exit code of the Windows executable.

about_Automatic_Variables | Microsoft TechNet

$?
   Contains the execution status of the last operation.
   It contains TRUE if the last operation succeeded and FALSE if it failed.
$LastExitCode
   Contains the exit code of the last Windows-based program that was run.

Case where the file is not a Windows executable

# Example of error
PS> $?
True    # Initial state
PS> $LASTEXITCODE
PS>     # Initial state is null
PS> $date = [datetime]"a"
エラーになる
PS> $?
False   # Failure is stored. Changed.
PS> $LASTEXITCODE
PS>     # Failure is not stored. Not changed, remains Null

Case of Windows executable. ping.exe example

# Example of success
PS> $?
False   # Previous failure state
PS> $LASTEXITCODE
1       # Exit code for previous failure
PS> ping EXIST_PC

-中略(成功)- 

PS> $?
True    # Success is stored. Changed.
PS> $LASTEXITCODE
0       # Success is stored. Changed.

# エラーになる例
PS> ping NO_EXIST_PC
ping 要求ではホスト NO_EXIST_PC が見つかりませんでしたホスト名を確認してもう一度実行してください
PS> $?
False   # Failure is stored. Changed.
PS> $LASTEXITCODE
1       # Failure is stored. Changed.

Summary

  • Use $? if you want to pick up the last error.
  • Use $LastExitCode if you want to pick up the exit code of Windows executable.

$Error

$Error is an automatic variable that stores information on errors that have occurred.
With $Error[0], you can output the latest error.
With $Error[-1], you can output the oldest error.

PS> $Error      # State with no error.
PS> throw 'Error!'
Exception: Error!
PS> throw 'Error!!'
Exception: Error!!
PS> throw 'Error!!!'
Exception: Error!!!
PS> $Error      # output errors information that have occurred.

Exception: Error!!!

Exception: Error!!

Exception: Error!
PS> $Error[0]   # Output the latest error.

Exception: Error!!!
PS> $Error[-1]  # Output the oldest error.

Exception: Error!

Checking the error type

You can check the fullname of the error type as shown below.

  • $_.exception.gettype().fullname
  • $error[0].exception.gettype().fullname

Step1 Checking the actual error type

To check the type of the error,
output $_.exception.gettype().fullname in the catch block.

function Main {
    try {
        throw New-Object System.NullReferenceException
    }
    catch {
        $_.exception.gettype().fullname
    }
}
 
Main
PS> .\script.ps1
System.NullReferenceException

We found that the type of the error is System.NullReferenceException.

Step2 Catch the error with the error type we checked.

Actually incorporate the above error type into the catch condition and see if it can be caught.

function Main {
    try {
        throw New-Object System.NullReferenceException
    }
    catch [System.NullReferenceException] {
        Write-Host "Catch"
    }
    catch {
        Write-Host "Catch other"
    }
}

Main

Step3 Result

I was able to catch the targeted error.

PS> .\script.ps1
Catch   # catch the targeted error. 

YouTube

Click here for a video explanation.

About Try Catch Finally | Microsoft Docs

About Trap | Microsoft Docs

about_Automatic_Variables | Microsoft TechNet

How can I rethrow an exception from catch block in PowerShell? | stackoverflow