PowerShell エラーハンドリングの方法について その1 Try-Catch編

PowerShell エラーハンドリングの方法について その1 Try-Catch編

こんにちは!やましー@データ活用クラウドエンジニア(@yamashi18041)です!

今日はPowerShellのエラーハンドリングについていろいろと調べて分かってきたのでまとめておきたいと思います。その中でも今回はTry-Catchについてです。

プログラムを製品として作る場合、正常系だけでなく異常系も考慮して作る必要があります。

そのためにエラーを捕捉して、対処を促したり、自動で復旧できるように処理を作りこむためにエラーハンドリングが必要になってきます。

これをしっかり実装できるかどうかがエンジニアとしての腕の見せ所ではないでしょうか。

PowerShell においてエラーハンドリングにはいくつかあると思いますのでそれぞれのやり方について考えてみたいと思います。

検証した環境はこんな感じ

PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.18362.145
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.18362.145
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

エラーハンドリングの種類

エラーハンドリングする方法にはいくつかパターンがります。

  • Try-Catch
  • Trap
  • $Error
  • $?
  • $LastExitCode
  • 戻り値

ハンドリング方法をざっくり並べるだけでもこれだけあります。

さらにエラーの発生元、例えば

  • コマンドレット
  • Throw
  • function
  • メソッド
  • ドットファイル形式
  • 外部プログラム

などにこれらが組み合わさって、理解をするのが困難です。

ということで、すべてのハンドリング方法について書こうと思っていたら、かなり記事が長くなってしまったので、それぞれのハンドリング方法ごとに記事を公開していきたいと思います。

今回は代表的なTry-Catchについての記事になります。

Try-Catchでエラーハンドリング

コマンドレットのエラーハンドリング

コマンドレットについてエラーハンドリングの手法を検証してみます。

これは多言語でもよくあるやり方ですね、例外が発生したらキャッチする。

基本構文としては

try {
  #例外が発生する可能性のあるコマンドレットをここに
} catch {
  #例外が発生した場合にのみ実行する処理をここに
} finally {
  #例外が発生しようがしまいが実行する処理をここに
}

さらにPowerShellの場合ひと手間加えないと例外をキャッチ出来ません。

その理由としては、PowerSehllのエラーには「中断されるエラー」と「中断されないエラー」があります。

Try-Catchでキャッチできるエラーは「中断されるエラー」です。

中断されるエラーとは「Throw」文によって発生したエラー。

それ以外のエラーは中断されないエラーと考えておけば問題ないです。

では中断されないエラーをキャッチするにはどうすればよいでしょうか。

キャッチするためには以下の2つ方法があります。

  • コマンドレットに 「-ErrorAction Stop」を毎回つける
  • ユーザー設定変数「$ErrorActionPreference = “Stop”」を設定しておく

こうすることにより「中断されないエラー」は「中断されるエラー」となります。

コマンドレットに 「-ErrorAction Stop」を毎回つける

tryする対象のコマンドレットのパラメータに毎回「-ErrorAction Stop」を付けます。

# -ErrorAction stopを付けた場合
try {
  Remove-Item C:\nonexistent\file.txt -ErrorAction stop
} catch {
  "キャッチ成功"
}
PS C:\> # -ErrorAction stopを付けた場合
PS C:\> try {
>>   Remove-Item C:\nonexistent\file.txt -ErrorAction stop
>> } catch {
>>   "キャッチ成功"
>> }
キャッチ成功

7行目で「キャッチ成功」と表示されているのが分かります。

次に付けなかった場合の例です

# -ErrorAction stopを付けていない場合
try {
  Remove-Item C:\nonexistent\file.txt
} catch {
  "キャッチ成功"
}
PS C:\> # -ErrorAction stopを付けていない場合
PS C:\> try {
>>   Remove-Item C:\nonexistent\file.txt
>> } catch {
>>   "キャッチ成功"
>> }
Remove-Item : パス 'C:\nonexistent\file.txt' が存在しないため検出できません。
発生場所 行:2 文字:3
+   Remove-Item C:\nonexistent\file.txt
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\nonexistent\file.txt:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

7行目以降例外が発出しているのが分かります。

ユーザー設定変数「$ErrorActionPreference = “Stop”」を設定しておく

ユーザー設定変数(preference variables)の「$ErrorActionPreference」に”Stop”をスクリプトの冒頭などで設定することでコマンドレットのデフォルトの動作を変更することができます。

詳しくはこちらのドキュメントをどうぞ

https://docs.microsoft.com/ja-jp/previous-versions/windows/powershell-scripting/hh847796(v=wps.640)?redirectedfrom=MSDN

$ErrorActionPreferenceはデフォルトのContinueの場合

$ErrorActionPreference
try {
  Remove-Item C:\nonexistent\file.txt
} catch {
  "キャッチ成功"
}
PS C:\> $ErrorActionPreference
Continue
PS C:\> try {
>>   Remove-Item C:\nonexistent\file.txt
>> } catch {
>>   "キャッチ成功"
>> }
Remove-Item : パス 'C:\nonexistent\file.txt' が存在しないため検出できません。
発生場所 行:2 文字:3
+   Remove-Item C:\nonexistent\file.txt
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\nonexistent\file.txt:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

8行目例外がキャッチできていません。

次に$ErrorActionPreferenceへStopを設定した場合

$ErrorActionPreference = "Stop"
try {
  Remove-Item C:\nonexistent\file.txt
} catch {
  "キャッチ成功"
}
PS C:\> $ErrorActionPreference = "Stop"
PS C:\> try {
>>   Remove-Item C:\nonexistent\file.txt
>> } catch {
>>   "キャッチ成功"
>> }
キャッチ成功

7行目で」「キャッチ成功」と表示されています。

特定の例外を指定してキャッチする

catchの後に例外クラスを記載することで、その例外のみを処理することができます。しかし、検証してみましたが、キャッチできる例外が限られているのであこの方法はあまりお勧めではないです。

例外別に処理を行いたい場合はキャッチした後にswitch文を使って処理を振り分けたらよさそうです。

try {
  #例外が発生する可能性のあるコマンドレットをここに
} catch [特定の例外クラス]{
  #特定の例外が発生した場合にのみ実行する処理をここに
} catch {
  #それ以外の例外が発生した場合に実行する処理をここに
} finally {
  #例外が発生しようがしまいが実行する処理をここに
}
try {
  #例外が発生する可能性のあるコマンドレットをここに
} catch {
     switch ($_.Exception.GetType().FullName) {
         "特定の例外クラス名1" {
             #特定の例外が発生した場合にのみ実行する処理をここに
         }
         "特定の例外クラス名2"  {
             #特定の例外が発生した場合にのみ実行する処理をここに
         }
         Default {
             #それ以外の例外が発生した場合に実行する処理をここに
         }
     }
} finally {
  #例外が発生しようがしまいが実行する処理をここに
}

下記のサイトにある通り、通常キャッチするための例外クラスはドキュメント化されていないので自分でエラーを発生させて見つけるしかないとのこと。

The possible exceptions for cmdlets are not usually documented, so you may need to find them on your own. When an exception occurs you can look up the error in the $error collection, or while inside a catch block under the $_ variable. Call the GetType() method on the base exception to extract the FullName property. Like shown here:

引用:https://docs.microsoft.com/ja-jp/archive/blogs/kebab/an-introduction-to-error-handling-in-powershell

エラーを発生させて $Errorか$_変数を用いて GetType()メソッドからFullNameを取得するのだそう。

PS C:> $Error[0].Exception.GetType().FullName
System.Management.Automation.ItemNotFoundException

$Errorは例外が発生したときのその例外が詰め込まれていく配列です。最新のものがインデックス0に入ります。

しかしどうもこれがあまり正しくなさそう。

以下の検証をしてみたのですが、キャッチする例外クラスの確認方法はそれぞれ異なりました。

  1. 存在しないファイル削除による例外をキャッチしてみる
    • $Error[0].GetType().FullName
  2. .Net Frameworkが投げる例外をキャッチしてみしてみる
    • $Error[0].FullyQualifiedErrorId
  3. ゼロ除算をキャッチしてみる
    • $Error[0].Exception.GetType().BaseType.FullName
  4. Throwをキャッチしてみる
    • $Error[0].Exception.GetType().FullName

存在しないファイル削除による例外をキャッチしてみる

Remove-Itemコマンドレットで存在しないファイルを削除したときの例外がどのようになるか確認してみました。

確認してみた結果-ErrorAction Stopを付けた場合と付けなかった場合で発生する例外が違うことが分かりました。

まずは-ErrorAction Stopをつけない場合の例外クラスを確認してみます。

Remove-Item C:\nonexistent\file.txt
$Error[0].GetType().FullName
$Error[0].Exception.GetType().FullName
PS C:\> Remove-Item C:\nonexistent\file.txt
Remove-Item : パス 'C:\nonexistent\file.txt' が存在しないため検出できません。
発生場所 行:1 文字:1
+ Remove-Item C:\nonexistent\file.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\nonexistent\file.txt:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

PS C:\> $Error[0].GetType().FullName
System.Management.Automation.ErrorRecord
PS C:\> $Error[0].Exception.GetType().FullName
System.Management.Automation.ItemNotFoundException

付けなかった場合の例外クラスは
[System.Management.Automation.ErrorRecord]
でした。
その中のExceptionプロパティに具体的な例外クラス[System.Management.Automation.ItemNotFoundException]
が紐づけられています。

次に-ErrorAction Stopをつけた場合の例外クラスを確認してみます。

Remove-Item C:\nonexistent\file.txt -ErrorAction Stop
$Error[0].GetType().FullName
$Error[0].ErrorRecord.GetType().FullName
$Error[0].ErrorRecord.Exception.GetType().FullName
PS C:\> Remove-Item C:\nonexistent\file.txt -ErrorAction Stop
Remove-Item : パス 'C:\nonexistent\file.txt' が存在しないため検出できません。
発生場所 行:1 文字:1
+ Remove-Item C:\nonexistent\file.txt -ErrorAction Stop
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\nonexistent\file.txt:String) [Remove-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand

PS C:\> $Error[0].GetType().FullName
System.Management.Automation.ActionPreferenceStopException
PS C:\> $Error[0].ErrorRecord.GetType().FullName
System.Management.Automation.ErrorRecord
PS C:\> $Error[0].ErrorRecord.Exception.GetType().FullName
System.Management.Automation.ItemNotFoundException

-ErrorAction Stopを付けた場合の例外クラスは
[System.Management.Automation.ActionPreferenceStopException]
でした。
その中のErrorRecordプロパティに[System.Management.Automation.ErrorRecord]
が紐づけられ、さらにその中のExceptionプロパティに具体的な例外クラス
[System.Management.Automation.ItemNotFoundException]
が紐づけられています。

どうやら -ErrorAction Stopを指定した場合は内部で一度元の例外を[ActionPreferenceStopException]に紐づけてから例外を発生させているようです。

図にしてみるとこんな感じです。

PowerShellの例外クラスの関係図

次に実際に例外をキャッチできるのか試してみます。

try {
  Remove-Item C:\nonexistent\file.txt -ErrorAction stop
} catch [Microsoft.PowerShell.Commands.WriteErrorException] {
     write-host 'WriteError'
} catch [System.Management.Automation.ItemNotFoundException] {
     write-host 'ItemNotFound'
} catch [System.Management.Automation.SessionStateException] {
     write-host 'SessionState'
} catch [System.Management.Automation.ActionPreferenceStopException] {
     write-host 'ActionPreferenceStopException'
} catch [System.Management.Automation.RuntimeException] {
     write-host 'RuntimeException'
} catch [System.FormatException] {
     write-host 'FormatException'
} catch [System.Management.Automation.ErrorRecord] {
     write-host 'ErrorRecord'
} catch [System.SystemException] {
     write-host 'SystemException'
} catch [System.Exception] {
     write-host 'Exception'
} catch {
     write-host 'Mmmm'
}
PS C:\> try {
>>   Remove-Item C:\nonexistent\file.txt -ErrorAction stop
>> } catch [Microsoft.PowerShell.Commands.WriteErrorException] {
>>      write-host 'WriteError'
>> } catch [System.Management.Automation.ItemNotFoundException] {
>>      write-host 'ItemNotFound'
>> } catch [System.Management.Automation.SessionStateException] {
>>      write-host 'SessionState'
>> } catch [System.Management.Automation.ActionPreferenceStopException] {
>>      write-host 'ActionPreferenceStopException'
>> } catch [System.Management.Automation.RuntimeException] {
>>      write-host 'RuntimeException'
>> } catch [System.FormatException] {
>>      write-host 'FormatException'
>> } catch [System.Management.Automation.ErrorRecord] {
>>      write-host 'ErrorRecord'
>> } catch [System.SystemException] {
>>      write-host 'SystemException'
>> } catch [System.Exception] {
>>      write-host 'Exception'
>> } catch {
>>      write-host 'Mmmm'
>> }
ActionPreferenceStopException

catchしたのは[System.Management.Automation.ActionPreferenceStopException]となりました。

当たり前ですが他のコマンドレットの場合も同様に例外はActionPreferenceStopExceptionでキャッチするので、catchによる条件分岐はあまりお勧めではありません。

なのでswitch分を使って分岐するようにすると良いと思います。

try {
  Remove-Item C:\nonexistent\file.txt -ErrorAction stop
} catch {
     switch ($_.Exception.GetType().FullName) {
         "Microsoft.PowerShell.Commands.WriteErrorException" {write-host "WriteError"}
         "System.Management.Automation.ItemNotFoundException"  {write-host "ItemNotFound"}
         Default {write-host $_.Exception.GetType().FullName}
     }
}

.Net Frameworkが投げる例外をキャッチしてみる

PowerShellの例外はPowershellそのものが投げる例外と.Net Frameworkのメソッドが投げる例外があるそうです。ということでどのような例外が返ってきて、キャッチできるのか見てみます。

[int]::Parse('test')
$Error[0].GetType().fullname
$Error[0].FullyQualifiedErrorId
$Error[0].Exception.GetType().fullname
try {
     [int]::Parse('test')
} catch [System.Management.Automation.MethodInvocationException] {
     write-host 'MethodInvocationException'
} catch [Microsoft.PowerShell.Commands.WriteErrorException] {
     write-host 'WriteError'
} catch [System.Management.Automation.ItemNotFoundException] {
     write-host 'ItemNotFound'
} catch [System.Management.Automation.SessionStateException] {
     write-host 'SessionState'
} catch [System.Management.Automation.ActionPreferenceStopException] {
     write-host 'ActionPreferenceStopException'
} catch [System.Management.Automation.RuntimeException] {
     write-host 'RuntimeException'
} catch [System.FormatException] {
     write-host 'FormatException'
} catch [System.Management.Automation.ErrorRecord] {
     write-host 'ErrorRecord'
} catch [System.SystemException] {
     write-host 'SystemException'
} catch [System.Exception] {
     write-host 'Exception'
} catch {
     write-host 'Mmmm'
}
PS C:\> [int]::Parse('test')
"1" 個の引数を指定して "Parse" を呼び出し中に例外が発生しました: "入力文字列の形式が正しくありません。"
発生場所 行:1 文字:1
+ [int]::Parse('test')
+ ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : FormatException

PS C:\> $Error[0].GetType().fullname
System.Management.Automation.ErrorRecord
PS C:\> $Error[0].FullyQualifiedErrorId
FormatException
PS C:\> $Error[0].Exception.GetType().fullname
System.Management.Automation.MethodInvocationException
PS C:\> try {
>>      [int]::Parse('test')
>> } catch [System.Management.Automation.MethodInvocationException] {
>>      write-host 'MethodInvocationException'
>> } catch [Microsoft.PowerShell.Commands.WriteErrorException] {
>>      write-host 'WriteError'
>> } catch [System.Management.Automation.ItemNotFoundException] {
>>      write-host 'ItemNotFound'
>> } catch [System.Management.Automation.SessionStateException] {
>>      write-host 'SessionState'
>> } catch [System.Management.Automation.ActionPreferenceStopException] {
>>      write-host 'ActionPreferenceStopException'
>> } catch [System.Management.Automation.RuntimeException] {
>>      write-host 'RuntimeException'
>> } catch [System.FormatException] {
>>      write-host 'FormatException'
>> } catch [System.Management.Automation.ErrorRecord] {
>>      write-host 'ErrorRecord'
>> } catch [System.SystemException] {
>>      write-host 'SystemException'
>> } catch [System.Exception] {
>>      write-host 'Exception'
>> } catch {
>>      write-host 'Mmmm'
>> }
FormatException

この場合11行目の$Error[0].FullyQualifiedErrorIdで確認した[FormatException]でキャッチできました。

ゼロ除算をキャッチしてみる

例外の定番0除算はどうなるのか見てみました。

$div = 1/0
$Error[0].GetType().fullname
$Error[0].FullyQualifiedErrorId
$Error[0].Exception.GetType().fullname
$Error[0].Exception.GetType().BaseType.FullName

try {
     $div = 1/0
} catch [System.Management.Automation.MethodInvocationException] {
     write-host 'MethodInvocationException'
} catch [Microsoft.PowerShell.Commands.WriteErrorException] {
     write-host 'WriteError'
} catch [System.Management.Automation.ItemNotFoundException] {
     write-host 'ItemNotFound'
} catch [System.Management.Automation.SessionStateException] {
     write-host 'SessionState'
} catch [System.Management.Automation.ActionPreferenceStopException] {
     write-host 'ActionPreferenceStopException'
} catch [System.Management.Automation.RuntimeException] {
     write-host 'RuntimeException'
} catch [System.FormatException] {
     write-host 'FormatException'
} catch [System.Management.Automation.ErrorRecord] {
     write-host 'ErrorRecord'
} catch [System.SystemException] {
     write-host 'SystemException'
} catch [System.Exception] {
     write-host 'Exception'
} catch {
     write-host 'Mmmm'
}
PS C:\> $div = 1/0
0 で除算しようとしました。
発生場所 行:1 文字:1
+ $div = 1/0
+ ~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

PS C:\> $Error[0].GetType().fullname
System.Management.Automation.ErrorRecord
PS C:\> $Error[0].FullyQualifiedErrorId
RuntimeException
PS C:\> $Error[0].Exception.GetType().fullname
System.Management.Automation.RuntimeException
PS C:\> $Error[0].Exception.GetType().BaseType.FullName
System.SystemException
PS C:\>
PS C:\> try {
>>      $div = 1/0
>> } catch [System.Management.Automation.MethodInvocationException] {
>>      write-host 'MethodInvocationException'
>> } catch [Microsoft.PowerShell.Commands.WriteErrorException] {
>>      write-host 'WriteError'
>> } catch [System.Management.Automation.ItemNotFoundException] {
>>      write-host 'ItemNotFound'
>> } catch [System.Management.Automation.SessionStateException] {
>>      write-host 'SessionState'
>> } catch [System.Management.Automation.ActionPreferenceStopException] {
>>      write-host 'ActionPreferenceStopException'
>> } catch [System.Management.Automation.RuntimeException] {
>>      write-host 'RuntimeException'
>> } catch [System.FormatException] {
>>      write-host 'FormatException'
>> } catch [System.Management.Automation.ErrorRecord] {
>>      write-host 'ErrorRecord'
>> } catch [System.SystemException] {
>>      write-host 'SystemException'
>> } catch [System.Exception] {
>>      write-host 'Exception'
>> } catch {
>>      write-host 'Mmmm'
>> }
SystemException

$Error[0].Exception.GetType().fullnameでは
[System.Management.Automation.RuntimeException]となっていますが、キャッチしたのは基底クラス?の[SystemException]という結果でした。

Throwをキャッチしてみる

Throwはプログラマが自ら例外を発生させたいときに使います。

Throwは様々なオブジェクトを例外として発報することができます。今回は単純にStringをThrowしてみます。ほかにも一度キャッチした例外を再度throwするなどの使い方もできます。

Throw "HogeHogeThrow"
$Error[0].GetType().FullName
$Error[0].Exception.GetType().FullName
$Error[0].Exception.ErrorRecord.GetType().FullName
try {
     Throw "HogeHogeThrow"
} catch [System.Management.Automation.MethodInvocationException] {
     write-host 'MethodInvocationException'
} catch [Microsoft.PowerShell.Commands.WriteErrorException] {
     write-host 'WriteError'
} catch [System.Management.Automation.ItemNotFoundException] {
     write-host 'ItemNotFound'
} catch [System.Management.Automation.SessionStateException] {
     write-host 'SessionState'
} catch [System.Management.Automation.ActionPreferenceStopException] {
     write-host 'ActionPreferenceStopException'
} catch [String] {
     write-host 'String'
} catch [System.Management.Automation.RuntimeException] {
     write-host 'RuntimeException'
} catch [System.FormatException] {
     write-host 'FormatException'
} catch [System.Management.Automation.ErrorRecord] {
     write-host 'ErrorRecord'
} catch [System.SystemException] {
     write-host 'SystemException'
} catch [System.Exception] {
     write-host 'Exception'
} catch {
     write-host 'Mmmm'
}
PS C:\> $Error[0].GetType().FullName
System.Management.Automation.ErrorRecord
PS C:\> $Error[0].Exception.GetType().FullName
System.Management.Automation.RuntimeException
PS C:\> $Error[0].Exception.ErrorRecord.GetType().FullName
System.Management.Automation.ErrorRecord
PS C:\> try {
>>      Throw "HogeHogeThrow"
>> } catch [System.Management.Automation.MethodInvocationException] {
>>      write-host 'MethodInvocationException'
>> } catch [Microsoft.PowerShell.Commands.WriteErrorException] {
>>      write-host 'WriteError'
>> } catch [System.Management.Automation.ItemNotFoundException] {
>>      write-host 'ItemNotFound'
>> } catch [System.Management.Automation.SessionStateException] {
>>      write-host 'SessionState'
>> } catch [System.Management.Automation.ActionPreferenceStopException] {
>>      write-host 'ActionPreferenceStopException'
>> } catch [String] {
>>      write-host 'String'
>> } catch [System.Management.Automation.RuntimeException] {
>>      write-host 'RuntimeException'
>> } catch [System.FormatException] {
>>      write-host 'FormatException'
>> } catch [System.Management.Automation.ErrorRecord] {
>>      write-host 'ErrorRecord'
>> } catch [System.SystemException] {
>>      write-host 'SystemException'
>> } catch [System.Exception] {
>>      write-host 'Exception'
>> } catch {
>>      write-host 'Mmmm'
>> }
RuntimeException

[RuntimeException]でキャッチでできました。20行目にStringを入れてみましたがさすがにそこには引っかかりませんでしたね。

ちなみにThrowで与えたオブジェクトはどこに入るかというと

PS C:\> $Error[0].TargetObject
HogeHogeThrow

TargetObjectプロパティに入っています。

まとめ

今回はPowerShellのエラーハンドリングその1として、Try-Catchについて検証を交えて解説してみました。

Try-Catchで大切なのは、コマンドレットは「中断されないエラー」なのでコマンドに毎回-ErrorAction Stopを指定するか、ユーザー設定変数$ErrorActionPreferenceに”Stop”を設定しておく必要があります。

そして、今回の記事を執筆中、様々な検証を通じてわかったこと。それはPowerShellのTry-Catchで例外クラス名を指定してキャッチするのは難しいということです。

なぜなら、Catch句で指定するための例外クラスは実際に試してみないとわからないからです。

キャッチするするときのキーとなる情報がErrorクラスのどこに書かれているかを今一度記載しておきます。

  1. 存在しないファイル削除による例外をキャッチしてみる
    ⇒$Error[0].GetType().FullName
  2. .Net Frameworkが投げる例外をキャッチしてみる
    ⇒$Error[0].FullyQualifiedErrorId
  3. ゼロ除算をキャッチしてみる
    ⇒$Error[0].Exception.GetType().BaseType.FullName
  4. Throwをキャッチしてみる
    ⇒$Error[0].Exception.GetType().FullName

処理を例外の種類に応じて振り分けたい場合はSwtch文で振り分ける方が難易度が低くバグを作りこみにくいと思いました。

次回はTrapによるエラーハンドリングについて記載してみたいと思います。

今回の記事でかなり$Error変数についても中身を確認したのですが、まだまだPowerShellは奥が深そうです。

最後までご覧いただきありがとうございました。

以上、やましー@データ活用クラウドエンジニア(@yamashi18041)でした。