エラー処理
try~catch~finallyステートメント
try~catch~finally
ステートメントで、エラー処理ができます。
構文
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'
}
実行例
PS C:\Users\user\Desktop> .\script.ps1
try
catch
用語 'aaa' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラ
ムの名前として認識されません。名前が正しく記述されていることを確認し、パスが含まれ
ている場合はそのパスが正しいことを確認してから、再試行してください。
finally
エラーの情報のアクセス方法
エラー内容やエラー箇所については、
$_
や$PSItem
、$_.ScriptStackTrace
などで確認でます。
scriptと実行例
script
script.ps1
$ErrorActionPreference = "Stop"
try {
Write-Host "Main:try"
Get-Content no_exist.txt # 存在しないファイルを開く
}
catch {
Write-Host "Main:catch"
Write-Host '$_:' $_
Write-Host '$PSItem:' $PSItem
Write-Host '$_.ScriptStackTrace:'
Write-Host $_.ScriptStackTrace
}
実行例
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
コマンドレットのエラー制御を指定する
$ErrorActionPreference
に値を設定することで、エラー発生時の挙動を指定できます。
PowerShellには、下記の表の通り、終了するエラーと終了しないエラーがあります。
値 | 挙動 |
---|---|
Continue | エラーを表示して、継続する。デフォルト値。 |
SilentlyContinue | エラーを表示しないで、継続する |
Ignore | SilentlyContinueと同様。しかし、$error配列にエラー内容を追記しない |
Inquire | ユーザーに対し確認プロンプトを表示する |
Stop | エラー発生時点で、処理を停止する |
終了するエラーはcatchされます。
一方、Continue
やSilentlyContinue
はcatchされません。
上記のSample Scriptでは、
先頭行で$ErrorActionPreference
をStop
にすることで、
エラーをcatchできるようにしています。
対象のコマンドレットのエラー制御を指定する -ErrorAction
全体のエラー制御ではなく、
対象のコマンドレットのエラーを制御したい場合は「-ErrorAction」で指定します。
「-ea」という風に省略することもも可能です。
こんな場合に便利
スクリプトの規模が大きい時に、全部のエラーはcatchしたくないが部分的なエラーをcatchしたい場合などに便利です。
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ステートメント
PowerShell V1の頃からあります。
PowerShell V2でtry~catch~finally
ステートメントが追加されたため、
trap
ステートメントを使用する機会は少ないかもしれません。
構文
trap [[<error type>]] {
<statement list>
}
trap
ステートメント内にbreak
をいれるかcontinue
をいれるかで、挙動を指定できます。
- どちらもなし:エラーを表示して、処理を継続する
break
:エラーを表示して、処理を終了するcontinue
:エラーを表示しないで、処理を継続する
breakもcontinueもない場合
Script
Write-Host "Pre"
no_exist_command
Write-Host "Post"
trap {
Write-Host "Trap"
}
実行結果
エラーを表示して処理を継続する。
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
breakの場合
Script
Write-Host "Pre"
no_exist_command
Write-Host "Post"
trap {
Write-Host "Trap"
break # 変更点
}
実行結果
エラーを表示して、処理を終了する。
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
continueの場合
Script
Write-Host "Pre"
no_exist_command
Write-Host "Post"
trap {
Write-Host "Trap"
continue # 変更点
}
実行結果
エラーを表示しないで、処理を継続する。
PS C:\Users\user\Desktop> .\script.ps1
Pre
Trap
Post
Visual Studio Codeでも、以下の違いがあるようです。
try~catch~finally
ステートメントは、入力支援されるtrap
ステートメントは、入力支援されない
エラーを発生させるthrow
エラーのthrow
PS> throw "Error!" # エラーメッセージを表示させる
Error!
At line:1 char:1
PS> throw New-Object System.NullReferenceException # 指定のエラーを発生させる
オブジェクト参照がオブジェクト インスタンスに設定されていません。
At line:1 char:1
エラーの再throw
下位関数内のcatchの中でthrow
すると、上位の関数のcatchにエラーを渡すことができます。
function Sub {
try {
Write-Host "Sub :try"
throw (Get-Date).ToString("yyyy/MM") # 最初のthrow
}
catch {
Write-Host "Sub :catch"
throw # 再throw
}
}
function Main {
try {
Write-Host "Main:try"
Sub
}
catch {
Write-Host "Main:catch"
Write-Host $_ # 受け取ったエラーを出力する
}
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
- 再throwには、
throw
がオススメ。 - 再throw時に
throw "Error Message"
などとすると、エラーの個数($error.Count
)が余分に1つ増えてしまうのでやめたほうが良いかもしれません。
stackoverflow How can I Rethrow an exception from catch block in Powershell?
エラー処理に関する自動変数
ここでは以下の3つの自動変数について見ていきます。
- $?
- $LastExitCode
- $Error
$?と$LastExitCode
エラーに関する自動変数として、
自動変数の$?
と$LastExitCode
があります。
2つの自動変数はそれぞれ異なる情報を格納します。
$?
は、最後の処理の結果が成功ならTrueを、失敗ならFalseを格納します。
$LastExitCode
は、Windowsの実行ファイルの終了コードを格納します。
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.
Windowsの実行ファイルでない場合
# エラーになる例
PS> $?
True # 初期状態
PS> $LASTEXITCODE
PS> # 初期状態はNull
PS> $date = [datetime]"a"
~エラーになる~
PS> $?
False # 失敗を格納している。変化した
PS> $LASTEXITCODE
PS> # 失敗を格納していない。変化していない、Nullのまま
Windows実行ファイルの場合 ping.exeの例
# 成功する例
PS> $?
False # 前回失敗している
PS> $LASTEXITCODE
1 # 前回失敗の終了コード
PS> ping EXIST_PC
-中略(成功)-
PS> $?
True # 成功を格納している。変化した
PS> $LASTEXITCODE
0 # 成功を格納している。変化した
# エラーになる例
PS> ping NO_EXIST_PC
ping 要求ではホスト NO_EXIST_PC が見つかりませんでした。ホスト名を確認してもう一度実行してください。
PS> $?
False # 失敗を格納している。変化した
PS> $LASTEXITCODE
1 # 失敗を格納している。変化した
まとめ
- 直前のエラーを拾いたい場合は
$?
を使用する - Windowsのexeの終了コードを拾いたい場合は
$LastExitCode
を使用する
$Error
$Error
は、発生したエラーの情報を格納する自動変数です。
$Error[0]
で、最新のエラーを出力できます。
$Error[-1]
で、最古のエラーを出力できます。
PS> $Error # エラーが発生していない状態
PS> throw 'Error!'
Exception: Error!
PS> throw 'Error!!'
Exception: Error!!
PS> throw 'Error!!!'
Exception: Error!!!
PS> $Error # 発生したエラーの情報を出力する
Exception: Error!!!
Exception: Error!!
Exception: Error!
PS> $Error[0] # 最新のエラーを出力する
Exception: Error!!!
PS> $Error[-1] # 最古のエラーを出力する
Exception: Error!
エラーの型を調べる
以下のようにエラーの型のfullnameを確認すると、エラーの型を調べられます。
- $_.exception.gettype().fullname
- $error[0].exception.gettype().fullname
Step1 実際にエラーの型を調べる
エラーの型を調べるために、
catchブロックの中で$_.exception.gettype().fullname
を出力します。
function Main {
try {
throw New-Object System.NullReferenceException
}
catch {
$_.exception.gettype().fullname
}
}
Main
PS> .\script.ps1
System.NullReferenceException
エラーの型が、System.NullReferenceException
であることがわかりました。
Step2 調べたエラーの型でエラーをcatchする
実際に上記のエラーの型をcatchの条件に組み込んで、catchできるか確かめます。
function Main {
try {
throw New-Object System.NullReferenceException
}
catch [System.NullReferenceException] {
Write-Host "Catch"
}
catch {
Write-Host "Catch other"
}
}
Main
Step3 結果
狙ったエラーをcatchできました。
PS> .\script.ps1
Catch # 狙ったエラーをcatchできた
YouTube
動画による説明はこちら。
参考資料
About Try Catch Finally | Microsoft Docs
about_Automatic_Variables | Microsoft TechNet
How can I rethrow an exception from catch block in PowerShell? | stackoverflow
スポンサーリンク