以下のような赤い壁のテキストのスクリプトやPowerShellのコマンドレットを実行したことはありますか?

エラーは圧倒的で混乱をもたらすことがあります。そして、エラーは読みにくいことが多いため、スクリプトのどこで何が間違っているのかを判断することはほぼ不可能です。
幸いなことに、PowerShellにはエラーハンドリングを通じてこれを改善するためのいくつかのオプションがあります。エラーハンドリングを使用すると、エラーをフィルタリングして表示することができ、理解しやすくなります。そして、エラーを理解することで、エラーハンドリングにさらなるロジックを追加することも簡単です。
この記事では、PowerShellでのエラーとエラーハンドリングを実行するためのPowerShellのTry Catch
ブロック(およびfinally
ブロック)について学びます。
PowerShellでエラーがどのように動作するかを理解する
エラーハンドリングに入る前に、まずPowerShellのエラーに関するいくつかの概念を理解しましょう。エラーの理解は、より良いエラーハンドリング戦略につながることがあります。
$Error
自動変数
PowerShellでは、多くの自動変数がありますが、その1つが$Error
自動変数です。PowerShellはセッションでエンカウントしたすべてのエラーを$Error
変数に格納します。$Error
変数は最新のエラーをソートしたエラーの配列です。
最初にPowerShellセッションを開くと、$Error
変数は空になります。 $Error
変数を呼び出すことで、それを確認できます。

上記のように、$Error
変数は空のままです。しかし、エラーが生成されると、エラーは$Error
変数に追加されて保存されます。
以下の例では、存在しないサービス名を意図的に取得することでエラーが生成されます。

上記の出力からわかるように、生成されたエラーは$Error
変数に追加されました。
$Error変数には、PowerShellセッションで生成されたエラーのコレクションが格納されています。各エラーは、配列の位置を呼び出すことでアクセスできます。最新のエラーは常にインデックス0にあります。
たとえば、最新のエラーは
$Error[0]
を使用して取得できます。
$Error
オブジェクトのプロパティ
PowerShellではすべてがオブジェクトである
ため、$Error
変数もオブジェクトであり、オブジェクトにはプロパティがあります。 $Error
変数をGet-Member
コマンドレットにパイプすると、利用可能なプロパティのリストが表示されます。

エラーの原因を特定するには、以下のコマンドを使用してInvocationInfo
プロパティの内容を表示できます。

同じように他のプロパティでも同様に操作し、他にどのような情報を見つけることができるかを発見できます!
終了エラー
終了エラーは、PowerShellが非終了エラーとは異なり、実行フローを停止します。終了エラーが発生する方法はいくつかあります。その一つの例は、存在しないパラメータを使用してコマンドレットを呼び出す場合です。
以下のスクリーンショットからわかるように、Get-Process notepad
というコマンドが実行されると、コマンドは有効であり、notepadプロセスの詳細が表示されます。

しかし、Get-Process notepad -handle 251
のように存在しないパラメータを使用すると、コマンドレットはhandle
パラメータが無効であるというエラーを表示します。その後、notepad
プロセスの詳細を表示せずにコマンドレットが終了します。

非終了エラー
非終了エラーは、スクリプトやコマンドの実行を停止しないエラーです。たとえば、以下のコードをご覧ください。このコードはfileslist.txtファイルからファイル名のリストを取得します。その後、スクリプトは各ファイル名を処理し、各ファイルの内容を読み取り、画面に出力します。
filelist.txtファイルの内容は以下のリストに表示されています。
しかし、File_6.logが実際に存在しなかった場合はどうでしょうか?コードを実行すると、スクリプトがFile_6.logを見つけることができないため、エラーが発生することが予想されます。以下のような出力が表示されます。

上記の結果のスクリーンショットからわかるように、スクリプトはリスト内の最初の5つのファイルを読み取ることができましたが、ファイルFile_6.txtを読み取ろうとしたときにエラーが発生しました。スクリプトはその後、終了する前に残りのファイルを読み取り続けました。スクリプトは終了しませんでした。
これまでに、終了するエラーと終了しないエラーについて学びましたが、終了しないエラーを終了するエラーとして扱うこともできることをご存知でしょうか?
PowerShellには、参照変数という概念があります。これらの変数は、PowerShellの振る舞いをさまざまな方法で変更するために使用されます。これらの変数の1つが$ErrorActionPreference
と呼ばれます。
$ErrorActionPreference
変数は、PowerShellが終了しないエラーをどのように処理するかを変更するために使用されます。デフォルトでは、$ErrorActionPreference
の値はContinue
に設定されています。$ErrorActionPreference
変数の値をSTOP
に変更すると、PowerShellはすべてのエラーを終了するエラーとして扱います。
$ErrorActionPreference
の値を変更するために、以下のコードを使用してください。
他の有効な$ErrorActionPreference変数の値については、PowerShell ErrorActionPreferenceを参照してください。
さて、この記事の非終了エラーセクションで使用された例に戻りましょう。次のコードのようにスクリプトを変更して、$ErrorActionPreference
の変更を含めることができます:
上記の変更されたコードを実行すると、$ErrorActionPreference
の値がデフォルト値のContinue
に設定されている場合とは異なる動作をします。

$ErrorActionPreference
variable上記の結果のスクリーンショットからわかるように、スクリプトはリスト内の最初の5つのファイルを読み取ることができましたが、ファイルFile_6.txtの読み取り時にファイルが見つからないためエラーが返されます。その後、スクリプトが終了し、残りのファイルは読み取られません。
$ErrorActionPreference
の値は現在のPowerShellセッションでのみ有効です。新しいPowerShellセッションが開始されると、デフォルト値にリセットされます。
ErrorAction
共通パラメータ
$ErrorActionPreference
の値がPowerShellセッションに適用されると、共通パラメータをサポートする任意のcmdletにErrorAction
パラメータが適用されます。ErrorAction
パラメータは、$ErrorActionPreference
変数と同じ値を受け入れます。
ErrorAction
パラメータの値が$ErrorActionPreference
の値より優先されます。
前の例と同じコードを使用して戻りましょう。ただし、今回はGet-Content
行にErrorAction
パラメータが追加されます。
変更したコードを実行すると、$ErrorActionPreference
がContinue
に設定されていても、スクリプトがエラーに遭遇すると終了します。スクリプトが終了するのは、Get-Content
のPowerShell ErrorAction
パラメータの値がSTOP
に設定されているためです。

ErrorAction
parameterPowerShellのTry Catchブロックの使用
ここまで、PowerShellのエラーや$ErrorActionPreference
変数とPowerShellのErrorAction
パラメータの動作について学びました。さあ、いよいよ面白い部分であるPowerShellのTry Catch Finally
ブロックについて学びましょう。
PowerShellのtry catch
ブロック(およびオプションのfinallyブロック
)は、コードの範囲を囲んで返されるエラーをキャッチする方法です。
以下のコードは、Try
ステートメントの構文を示しています。
Try
ブロックには、PowerShellによってエラーを「試し」て監視するコードが含まれています。 Try
ブロックのコードがエラーに遭遇すると、エラーは$Error
変数に追加され、Catch
ブロックに渡されます。
Catch
ブロックには、Try
ブロックからエラーを受け取った場合に実行するアクションが含まれています。 Try
ステートメントには複数のCatch
ブロックがある場合があります。
Finally
ブロックには、Try
ステートメントの最後に実行されるコードが含まれています。このブロックはエラーが発生したかどうかに関係なく実行されます。
PowerShell ErrorActionを使用して非特定のエラー(キャッチオール)をキャッチする
A simple Try
statement contains a Try
and a Catch
block. The Finally
block is optional.
たとえば、非特定の例外をキャッチするには、Catch
パラメータは空にする必要があります。以下の例のコードは、$ErrorActionPreference変数セクションで使用されたスクリプトと同じものですが、Try Catch
ブロックを使用するように変更されています。
以下のコードからわかるように、今回はforeach
ステートメントがTry
ブロック内に含まれています。その後、Catch
ブロックには、エラーが発生した場合に文字列「An Error Occurred」を表示するコードが含まれています。 Finally
ブロック内のコードは、$Error
変数をクリアするだけです。
上記のコードは、PowerShellで実行すると、以下に示す出力が表示されます。

上記の出力は、スクリプトがエラーに遭遇し、Catch
ブロック内のコードを実行してから終了したことを示しています。
エラーは処理され、それがエラーハンドリングのポイントでした。ただし、表示されるエラーはあまりにも一般的でした。より詳細なエラーを表示するには、Try
ブロックによって渡されたエラーのException
プロパティにアクセスすることができます。
以下のコードは、特にCatch
ブロック内のコードを修正し、パイプラインから渡された現在のエラーの例外メッセージを表示するように変更されています – $PSItem.Exception.Message
今回、修正されたコードを実行すると、表示されるメッセージはより詳細になります。

特定のエラーのキャッチ
キャッチオールのエラーハンドリングが最も適切なアプローチではない場合もあります。おそらく、スクリプトがエンカウントしたエラーのタイプに依存するアクションを実行したいと思うかもしれません。
エラータイプをどのように決定しますか?直近のエラーのException
プロパティのTypeName
値をチェックすることで判断できます。たとえば、前の例からエラータイプを見つけるには、次のコマンドを使用します:
上記のコードの結果は、以下のスクリーンショットのようになります。TypeName
の値が表示されていることがわかります – System.Management.Automation.ItemNotFoundException
。

エラータイプがわかったので、特定のエラーをキャッチするためにコードを変更してください。以下の修正後のコードからわかるように、2つの Catch
ブロックがあります。最初の Catch
ブロックは特定のエラータイプ (System.Management.Automation.ItemNotFoundException
) をキャッチします。一方、2番目の Catch
ブロックには一般的な、キャッチオールのエラーメッセージが含まれています。
以下のスクリーンショットは、上記の修正後のコードの出力例です。

結論
この記事では、PowerShell のエラー、そのプロパティ、およびエラーの特定のタイプを判断する方法について学びました。また、$ErrorActionPreference
変数と PowerShell の ErrorAction
パラメータが非終了エラーの扱いにどのように影響するかの違いも学びました。
また、PowerShell の Try Catch Finally
ブロックを使用して、特定のエラーやキャッチオールのアプローチによるエラーハンドリングを行う方法も学びました。
この記事で示されている例は、Try Catch Finally
ブロックの基本的な動作を示すものです。この記事で得た知識を活用して、スクリプトでエラーハンドリングを開始するための出発点として活用してください。