Error Handling
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”.
Useful case
This is useful if your script is very large and you don’t want to catch all errors, but want to catch partial errors.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
In Visual Studio Code, there seems to be the following differences.
- For
try~catch~finally
statements, input support is provided. - For
trap
statements, input support is not provided.
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.
Reference Links
About Try Catch Finally | Microsoft Docs
about_Automatic_Variables | Microsoft TechNet
How can I rethrow an exception from catch block in PowerShell? | stackoverflow