PowerShell の Try-Catch:エラー処理ガイド
Aug 25, 2025
PowerShell のエラーハンドリングでは、Try-Catch-Finally ブロックを使用して、終了(terminating)エラーと非終了(non-terminating)エラーの両方を管理し、無人実行でもスクリプトの信頼性を維持します。Try はリスクのあるコードを囲み、Catch は例外に応答し、Finally はリソースをクリーンアップします。たとえば -ErrorAction, $ErrorActionPreference や $Error を用いることで、管理者は厳格な処理を適用し、詳細なエラーメッセージを取得し、復旧を自動化できます。このアプローチにより、ダウンタイムを削減し、データ損失を防ぎ、スケールに応じた堅牢なスクリプト作成を可能にします。
PowerShell におけるエラーハンドリング入門
多くの PowerShell スクリプトは無人で実行されるように設計されているため、エラーをスムーズに処理できることを確実にするのが非常に重要です。適切なエラー処理は、不完全な処理やシステム停止からデータ損失まで、さまざまな問題の発生を防ぐのに役立ちます。エラー処理では、スクリプトの実行を停止する「終了(terminating)エラー」と、スクリプトは実行を継続できるものの出力に影響する可能性がある「非終了(non-terminating)エラー」の両方を考慮する必要があります。
PowerShell におけるエラー処理のための最も有用な仕組みの 1 つが Try-Catch-Finally ブロックです。Try ブロックには、例外をスローする可能性のあるコードが含まれています。そうした場合、制御は Catch ブロックに移されます。このブロックは、問題のあるファイルのスキップや無効な入力の処理などのアクションを行うとともに、イベントをログに記録することでエラーを処理します。Finally ブロックは常に実行され、ファイルを閉じる、リソースを解放する、または情報をログに記録するなどの後処理(クリーンアップ)を行います。たとえば、PowerShell で Try Catch の詳細なエラーメッセージを作成することで、問題を解決するための適切な対応を取れるようになります。
このドキュメントでは Try-Catch-Finally ブロックを詳しく解説します。あわせて、PowerShell における他のエラー処理方法として、ErrorAction パラメーターを使って cmdlet がエラーにどのように応答するかを制御する方法や、$Error 変数を使ってエラー履歴を保存する方法も取り上げます。
PowerShell におけるエラーとは?
エラーとは、スクリプトの通常の実行フローに影響を与えたり、完全に実行を停止させたりする可能性のある事象です。よくある原因には、文法の誤り、ファイルの欠落、権限不足、または利用できないリソースなどがあります。エラーには主に2種類あり、terminating errors(致命的エラー)とnon-terminating errors(非致命的エラー)です。
Terminating Errors:スクリプトを停止させる重大なエラー
terminating errors は、適切に処理されない限り、直ちにスクリプトの実行を停止します。これらのエラーは、PowerShell が復旧できない問題に直面したときに発生します。たとえば構文エラー、存在しない変数やファイルの呼び出し、または要求された操作を実行するための権限が不足している場合などです。
たとえば、以下のスクリプトはファイル users.txt を取得しようとします。:
Get-Content C:\users.txt | Get-ADUser -Properties name | Select-Object -Property SamAccountName,name
このファイルが指定された場所に存在しない場合、またはスクリプトを実行しているアカウントにそれへアクセスする権限がない場合、スクリプトは terminating error を生成し、以下のようにスクリプトの動作を停止します。:
非終了エラー:スクリプトの実行を継続できるエラー
PowerShell の非終了エラーとは、スクリプトの実行を停止しないエラーです。これらのエラーは、複数のオブジェクトを処理しようとする cmdlet によってよく発生します。1 件の失敗が必ずしもスクリプト全体の停止につながるわけではありません。
たとえば、前の例で使用したスクリプトを実行するとしますが、今回はファイルが存在し、アクセスするための権限もあるとします。とはいえ、ドメイン コントローラーへの接続ができません。この場合、最初のコマンドは実行され、ファイルの内容が取得されます。しかし、次のコマンドは失敗し、ファイル内の3つのオブジェクトそれぞれについて非終了エラーが生成されます。
次に、ドメイン コントローラーへの接続が復旧したものの、ファイル内の1つのオブジェクトに無効なユーザー名があるとします。スクリプトを実行すると、そのオブジェクトに対して下に示す非終了エラーが生成されますが、他のオブジェクトはスクリプトによって処理されます。
エラーの保存場所:$Error 変数
$Error は、スクリプトの実行中に遭遇した直近のエラーを格納する自動配列であり、スクリプトのデバッグやトラブルシューティングに非常に役立ちます。最も新しいエラーはインデックス [0] に保存されます。
たとえば、次のスクリプトが存在しないファイルを取得しようとすると、生成されたエラーを $Error から取得し、親しみやすいメッセージとして表示します:
# trying to get a file which doesn't exist, and an error is generated.
Get-Item "C:\file44.txt"
# Display a message along with the last error.
Write-Host "Oops! Something went wrong Here's the error: $($Error[0])"
Try、Catch、Finally ブロックを理解する
エラーをスムーズに処理する良い方法は、Try-Catch-Finally ブロックを実装することです。
Active Directory とは?
eBook をダウンロード
Try ブロック:エラーが起こり得るコードが配置される場所
Try ブロックは、エラーが発生する可能性のあるコードを囲みます。たとえば、次のスクリプトはメモ帳(Notepad)プロセスを停止するように設計されています。Try ブロックは、そのプロセスが現在実行中であれば停止しますが、実行されていない場合は、Catch ブロックに処理が移り、スクリプトのクラッシュを防ぎます。
try {
# Attempt to stop a process that may not be running
Stop-Process -Name "Notepad" -ErrorAction Stop
# If no error occurs, this line will execute
Write-Host "Notepad process stopped successfully."
}
catch {
# Handle the error gracefully
Write-Host "Oops! Could not stop the process. Error: $($_.Exception.Message)"
}
Catch ブロック:エラーが発生したときの処理
Catch ブロックは、Try ブロック内で発生した例外を処理するために使用されます。次の PowerShell Try Catch の例では、スクリプトはユーザーに数値の入力を求め、その数値で 10 を割って結果を表示します。ただし、入力された数値が 0 の場合は、0 で割ることができないため、割り算を試みるとエラーになります。その場合は Catch ブロックが実行され、数値の代わりにエラーメッセージが表示されます。
try {
$number = [int](Read-Host "Enter a number")
Write-Output "Result: $(10 / $number)"
}
catch {
Write-Output "Error: Invalid input or division by zero!"
}
finally {
Write-Output "Program execution completed."
}
Finally ブロック:エラーが発生してもしなくても必ず実行されるコード
Finally ブロックは、例外がスローされたかどうかに関わらず、必ず実行されます。
たとえば、次のスクリプトは要素が3つだけの配列を定義しているのに、5番目の要素を出力しようとします。この例外は Catch ブロックで処理され、エラーが表示されます。ですが、Finally ブロックも実行されるため、追加のメッセージが表示されます。
try {
# Define an array
$numbers = @(1, 2, 3)
# Access an invalid index using a .NET method that throws an exception
$value = $numbers.GetValue(5)
Write-Host "Value: $value"
}
catch [System.IndexOutOfRangeException] {
# Handle the specific exception
Write-Host "Error: Index out of range exception caught."
}
finally {
# This block always executes
Write-Host "Execution completed."
}
高度な例:異なる種類の例外に対して複数の Catch ブロックを使用する
スクリプトには、さまざまな種類の例外を処理するために複数の Catch ブロックを含めることで、よりきめ細かいエラー処理が可能になります。実際に、.Net フレームワークは、以下を含む PowerShell Try Catch の例外メッセージの種類を豊富に用意しています:
- System.DivideByZeroException — 任意の数を 0 で割ろうとしたときに発生します
- System.FormatException — 数値ではない入力を数値に変換しようとすると発生します
- System.ArgumentNullException — 渡された引数が null ですが、本来 null であるべきではない場合に発生します
- System.IO.IOException — I/O エラーが発生したときにスローされます
たとえば、次のスクリプトはユーザーに 2 つの数字の入力を求め、それらを整数形式に変換したうえで、最初の数字を 2 番目の数字で割り、結果を出力します。最初の Catch ブロックは、ユーザーの入力を整数形式に変換できない可能性を扱い、次の Catch ブロックは、ゼロで除算しようとする可能性を扱います。
try {
# Prompt user for first input
$num1 = Read-Host "Enter the first number"
$num1 = [int]$num1 # Convert to integer (may cause FormatException)
# Prompt user for second input
$num2 = Read-Host "Enter the second number"
$num2 = [int]$num2 # Convert to integer (may cause FormatException)
# Perform division (may cause DivideByZeroException)
$result = $num1 / $num2
# Print result
Write-Host "Result: $result"
}
catch [System.FormatException] {
# Handling invalid input error
Write-Host "Error: Please enter only numeric values!"
}
catch [System.DivideByZeroException] {
# Handling division by zero error
Write-Host "Error: Cannot divide by zero!"
}
catch {
# Handling unexpected errors
Write-Host "An unexpected error occurred: $_"
}
finally {
# Code that always runs
Write-Host "Execution completed."
}
高度なエラー処理テクニック
より堅牢で保守しやすいスクリプトを作成するには、次のエラー処理テクニックを PowerShell と組み合わせて使用することを検討してください Try and Catch ブロック:
- 次を使用します $ErrorActionPreference = “Stop” すべてのエラーを終了(terminating)として扱うようにし、キャッチしやすくします。
- 個々のコマンドに -ErrorAction Stop を指定して、スクリプト全体に影響を与えずに、よりきめ細かな制御を可能にします。
- 次を使用して $_.Exception.Message と $PSItem のエラー詳細にアクセスします。
特定の例外をキャッチする
次のスクリプトは、ユーザーからの入力をユーザーから整数に変換し、その後コマンドを実行することを目的としています。最初の Catch ブロックは無効なユーザー入力の可能性を処理し、2つ目のブロックは無効なコマンドを実行しようとする試みを処理します。どちらかの例外が発生した場合、スクリプトはカスタムメッセージを出力します。
try {
# Attempt to convert user input to an integer (may throw FormatException)
$number = Read-Host "Enter a number"
$number = [int]$number
# Try running a non-existent command (may throw CommandNotFoundException)
NonExistent-Command
}
catch [System.FormatException] {
Write-Host "Error: Invalid input. Please enter a valid number."
}
catch [System.Management.Automation.CommandNotFoundException] {
Write-Host "Error: Command not found. Please check the command name."
}
catch {
Write-Host "An unexpected error occurred: $_"
}
finally {
Write-Host "Execution completed."
}
$_.Exception.Message と $PSItem を使ってエラーの詳細にアクセスする
Catch ブロック内でエラーの詳細にアクセスするには、次の変数を使用できます。
- $_.Exception.Message は、エラーの関連部分だけを含む、分かりやすくユーザーフレンドリーな Try Catch の PowerShell エラーメッセージを提供します。
- $PSItem は、エラーの種類、発生元、スタックトレースを含む完全なエラーオブジェクトを保持します。
次のスクリプトは、これらの変数によって提供される出力の違いを示しています:
try {
# Attempt to open a non-existent file
Get-Content "C:\File1.txt" -ErrorAction Stop
}
catch {
# Using $_.Exception.Message to get detailed error information
Write-Host "Error occurred: $($_.Exception.Message)"
# Using $PSItem (same as $_) to display full error details
Write-Host "Full Error Details: $PSItem"
}
finally {
Write-Host "Execution completed."
}
Trap ステートメントの使用
A Trap ステートメントは、スクリプトのどこでエラーが発生しても、特定のエラーが発生したときに実行されるコードを定義します。その結果、個々の PowerShell Try-Catch ブロックよりも高い(グローバル)レベルでエラーを処理するための仕組みを提供します。
次のスクリプトでは、ゼロで割ろうとする試みが行われる可能性を処理するために、PowerShell で Try-Catch を使用します。この場合、Trap ステートメントは、発生し得るその他のエラーも捕捉します。具体的には、存在しないファイルで Get-Item cmdlet を使用することです。
# Global error handler using trap
trap {
Write-Host "Global Error Handler (trap): $_"
continue # Allows the script to continue execution
}
function Test-TryCatch {
try {
Write-Host "Inside Try Block"
1 / 0 # This will cause a division by zero error
Write-Host "This line will not execute due to the error above."
} catch {
Write-Host "Caught in Try-Catch: $_"
}
}
Write-Host "Before function call"
Test-TryCatch
Write-Host "After function call"
# Triggering another error outside try-catch to see if trap works
Write-Host "Triggering an error outside Try-Catch"
Get-Item "C:\NonExistentFile.txt" -ErrorAction Stop # Force a terminating error
Write-Host "Script completed"
PowerShell における非終端エラー(Non-Terminating Errors)の処理
Catch ブロックは、終了(terminating)エラーを処理するように設計されています。非終了(non-terminating)エラーはスクリプトの実行を停止しないため、Catch ブロックはトリガーされません。とはいえ、-ErrorAction Stop パラメーターを使うことで、非終了エラーを終了エラーに変換できます。このパラメーターにより、スクリプトは非終了エラーを終了エラーとして扱うよう強制されるため、Catch ブロックがそれらを適切に処理できるようになります。
次のスクリプトを実行するとしますが、アクセスしようとしているフォルダーが存在しない場合を考えてみてください。Try ブロックは -ErrorAction Stop によって、この非終了エラーを終了エラーに変換し、Catch ブロックで処理されるようにします。
$directoryPath = "C:\NonExistentFolder"
try {
Write-Host "Checking if directory exists..."
Get-ChildItem -Path $directoryPath -ErrorAction Stop # Force a terminating error if the directory doesn't exist
Write-Host "Directory found."
} catch {
Write-Host "Error: The directory '$directoryPath' was not found."
}
PowerShell で Try-Catch を使うためのベストプラクティス
コードの明確さ、効率、保守性を最大化するために、エラー処理ブロックは慎重に作成してください。特に PowerShell Try-Catch は、本当に例外が発生する場合にのみ使用すべきです。Try ブロック内のコードを、例外をスローし得る操作のみに絞ることで、例外の原因を特定しやすくなり、スクリプトのデバッグもしやすくなります。その他のケースでは if-else または switch のステートメントを検討してください。
その他の重要なベストプラクティスは次のとおりです。
- ‘Try’ ブロック内のコードが、単一責任の原則(single responsibility principle)に従っていることを確認してください。つまり、コードの各部分は特定のタスクを実行する必要があります。
- 異なる種類の例外を処理するために、別々の Catch ブロックを使用してください。
- コードを後片付けし、リソースを解放するために、必ず Finally ブロックを含めてください。
次のスクリプトは、これらのベストプラクティスの一部を示します。if ステートメントと test-path を使って、アクセスを試みる前にファイルが存在するかどうかを確認します。ファイルが存在しない場合は、else ステートメントを用いてエラーを表示します。Try-Catch ブロックはファイルの内容を読むためだけに使用されます。スクリプトが権限不足のようなエラーに遭遇した場合は、Catch ブロックが例外を処理し、エラーメッセージを表示します。
# Define the path to the file
$filePath = "D:\NonExistentFile.txt"
# Check if the file exists
if (Test-Path -Path $filePath) {
try {
# Try to read the file contents
$fileContents = Get-Content -Path $filePath -ErrorAction Stop
Write-Host "File contents: $fileContents"
}
catch {
# Handle any exceptions that occur while reading the file
Write-Host "Error: Unable to read the file. Exception Message: $_"
}
} else {
# If the file does not exist, display an error message
Write-Host "Error: The file does not exist."
}
PowerShell Try-Catch とスクリプトの継続実行
Continue ステートメントの使用
スクリプトが Try-Catch ブロック内でエラーに遭遇すると、既定の動作は、スクリプトが Catch ブロックで例外を処理し、実行を停止することです。ただし、ファイルのバッチ処理や複数のサーバーへの接続テストのように、エラー処理後も実行を継続したい場面があります。
1 回の失敗で反復全体が止まらないようにするには、Continue ステートメントを使用します。たとえば、次のスクリプトは複数のサーバーの接続をテストします。Continue ステートメントにより、どれか1 台のサーバーでエラーが発生しても実行が継続されます。
# List of server names (replace with actual server names or IPs)
$servers = @("lhehost9", "lhehost11", "lhehost10")
foreach ($server in $servers) {
try {
Write-Host "Attempting to connect to $server..."
# Simulating a remote connection (Replace with actual connection command)
Test-Connection -ComputerName $server -Count 2 -ErrorAction Stop
Write-Host "Successfully connected to $server.`n"
} catch {
Write-Host "Error: Failed to connect to $server. Skipping to next server...`n"
continue # Continue to the next server in the loop
}
}
Write-Host "Script execution completed."
$ErrorActionPreference 変数の使用
エラーが発生してもスクリプトの実行を継続させる別の方法は、$ErrorActionPreference 変数を使用することです。Try-Catch ブロックは局所的なエラー処理を可能にしますが、$ErrorActionPreference は、非終了(non-terminating)エラーに対する PowerShell の応答を制御するグローバル設定です。
すでに、$ErrorActionPreference を “Stop” に設定すると、すべてのエラーを終了(terminating)として扱えるため、エラーを捕捉しやすくなることを確認しました。 ただし、この変数には次の Continue(デフォルト)、Silentlycontinue、Inquire、Ignore などの追加設定もあります。この変数の設定を選ぶことで、スクリプト全体でエラーをどのように管理するかを定義できます。
PowerShell の Finally ブロック:リソースの後始末を確実に行う
先ほど述べたとおり、Finally ブロックは、スクリプト実行中にエラーが発生したかどうかに関わらず、Try と Catch ブロックの後で実行されます。ファイルを閉じる、接続を終了する、リソースを解放するなどの後始末(クリーンアップ)のために使われることが多いです。
たとえば、次のスクリプトはファイルを開いて、その中に “hello world” を書き込みます。エラーが発生した場合は Catch ブロックがメッセージを表示します。いずれにせよ、Finally ブロックによってファイルストリームが確実に閉じられ、リソースの漏えいを防ぎます。
try {
$filePath = "D:\Office\Backup\eventviewer_logs.txt"
$fileStream = [System.IO.StreamWriter]::new($filePath)
$fileStream.WriteLine("Hello, World!")
}
catch {
Write-Host "An error occurred: $_"
}
finally {
if ($fileStream) {
$fileStream.Close()
Write-Host "File stream closed successfully."
}
}
PowerShell で複数のエラーを扱う
エラーを保存して数える変数
PowerShell では、複数の例外に遭遇するスクリプトを監査およびデバッグする際に役立つ 2 つの変数が用意されています:
- $Error は、セッション中に遭遇したエラーの一覧を保持します。
- $Error.count は、現在のセッションで記録されたエラーの総数を示します。
正確に追跡するには、セッション中に必要に応じて時々エラーの一覧をクリアすることが必要になる場合があります。 $Error.clear() を使用すると、保存されているすべてのエラーが削除されます。
複数のエラーを処理するためにネストされた Try-Catch ブロックを使用する
次のスクリプトには、0 で割ろうとすることと、存在しないファイルにアクセスしようとすることという、2 つの異なる可能性のあるエラーを処理するための、2 つの入れ子になった Try-Catch ブロックが含まれています。:
try {
Write-Host "Starting First try block..."
try {
Write-Host "Attempting to divide by zero..."
$result = 1 / 0 # This will cause a divide-by-zero exception
}
catch [System.DivideByZeroException] {
Write-Host "Inner catch: Division by zero error occurred"
throw "Re-throwing error to outer try block"
}
try {
Write-Host "Accessing a file that doesn't exist..."
Get-Content -Path "C:\File1.txt" -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
Write-Host "Inner catch: File not found error occurred"
}
}
catch {
Write-Host "Outer catch: Handling an error from inner blocks - $($_.Exception.Message)"
}
finally {
Write-Host "Executing final block for cleanup..."
}
PowerShell におけるエラーメッセージとデバッグ
詳細なエラー情報へのアクセス
スクリプトの実行中にエラーが発生した場合、エラーが起きたことを知るだけでは不十分です。問題を診断して修正するためには、詳細情報が必要です。先ほど述べたとおり、$Error 変数はエラー記録の配列を保持しており、最も最近のエラーは $Error[0] にあります。特定のエラーのプロパティには Exception、CategoryInfo、InvocationInfo 、および ScriptStackTrace が含まれます。
ScriptStackTrace プロパティは非常に役立ちます。なぜなら、詳細なコールスタックを提供し、エラーにつながった関数呼び出しの順序とスクリプト上の場所を示してくれるからです。最新のエラーに対してこの詳細情報にアクセスするには、$Error[0].ScriptStackTrace を使用します。
カスタムエラーメッセージを提供する
意味のある、ユーザーフレンドリーなエラーメッセージを表示することで、スクリプトの使いやすさとデバッグが向上します。カスタムメッセージは、何がうまくいかなかったのかをユーザーが理解するための手がかりを提供し、場合によっては、不正なファイルパス、誤ったプロセス名、または権限不足などを修正することでエラーを直すのに役立ちます。
カスタムメッセージを表示するには、Write-host または write-error を Catch ブロック内で使用します。追加の詳細を提供するために $_.Exception.message を含めてください。
たとえば、次のスクリプトの実行中にエラー(ゼロ除算)が発生した場合、詳細な通知がコンソールに出力されるだけでなく、管理者にメールでも送信されます:
$SMTPServer = "lvkex.ca.lo"
$SMTPPort = 587
$From = "aadministrator@ca.lo"
$To = "administrator@ca.lo"
$Subject = "PowerShell Script Error Alert"
try {
Write-Host "Executing script..."
# Simulate an error (divide by zero)
$result = 1 / 0
}
catch {
# Capture actual error message details
$ErrorMessage = @"
An error occurred in the PowerShell script.
Message: $($_.Exception.Message)
Script: $($MyInvocation.ScriptName)
Line: $($_.InvocationInfo.ScriptLineNumber)
Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
"@
# Log error to console and send email
Write-Host "An error occurred. Sending email notification..."
Send-MailMessage -SmtpServer $SMTPServer -Port $SMTPPort -From $From -To $To -Subject $Subject -Body $ErrorMessage
}
}
PowerShell Try-Catch のよくあるユースケース
データ入力時のエラーを処理しながらユーザープロファイルを一括更新する
管理者は、csv ファイルに基づいて Active Directory のユーザー情報を自動的に更新するために、PowerShell をよく使用します。入力ファイルには無効なデータが含まれている可能性があるため、Try-Catch を使ってエラーを処理し、ログに記録することが重要です。
次のスクリプトは、ユーザーのリストを含む csv ファイルをインポートし、それを順に処理して AD 内のユーザー説明を更新します。結果はコンソールに出力し、エラーがあればログ ファイルに記録します。
# Define file paths
$CsvFile = "C:\Members (7).csv"
$LogFile = "C:\logs.txt"
# Import CSV
$Users = Import-Csv -Path $CsvFile
foreach ($User in $Users) {
try {
# Attempt to find the user in AD using CN or SamAccountName
$ADUser = Get-ADUser -LDAPFilter "(cn=$($User.cn))" -Properties SamAccountName, Description -ErrorAction SilentlyContinue
if ($ADUser -eq $null) {
# Log missing users
$ErrorMessage = "$(Get-Date): User '$($User.cn)' not found in AD."
Write-Host $ErrorMessage
Add-Content -Path $LogFile -Value $ErrorMessage
continue # Skip to the next user
}
# Define new description
$NewDescription = "Test update on $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
# Update AD user description
Set-ADUser -Identity $ADUser.SamAccountName -Description $NewDescription -ErrorAction Stop
# Log success
Write-Host "Updated: $($ADUser.SamAccountName) - New Description: $NewDescription"
}
catch {
# Capture and log errors
$ErrorMessage = "$(Get-Date): Error updating $($User.cn) ($($ADUser.SamAccountName)) - $($_.Exception.Message)"
Write-Host $ErrorMessage
Add-Content -Path $LogFile -Value $ErrorMessage
}
}
サーバーまたはネットワーク接続の問題への対処
Try-Catch ブロックは、サーバーやネットワーク接続の問題を扱う場合にも役立ちます。たとえば次のスクリプトは、正しい名前と誤った名前のそれぞれでサーバーへの接続をテストする方法を示しています:
# Define server details
$Server = "ada1.adatum.local"
$LogFile = "C:\log.txt"
try {
# Check if the server responds to a ping
$PingTest = Test-NetConnection -ComputerName $Server
if (-not $PingTest.PingSucceeded) {
throw "Server $Server is not responding to ping."
}
# Check RDP connectivity (port 3389)
$RDPTest = Test-NetConnection -ComputerName $Server -Port 3389
if (-not $RDPTest.TcpTestSucceeded) {
throw "Server $Server is reachable but RDP port 3389 is not open."
}
# If both checks pass
Write-Host "Server $Server is reachable, and RDP is accessible."
}
catch {
# Capture and log the error
$ErrorMessage = "$(Get-Date): Error connecting to server $Server - $($_.Exception.Message)"
Write-Host $ErrorMessage
Add-Content -Path $LogFile -Value $ErrorMessage
}
結論
Try-Catch-Finally ブロックは、PowerShell スクリプトでエラーを処理するための非常に貴重な手段です。これらを ErrorAction パラメーターや $ErrorActionPreference と $Error 変数と組み合わせることで、予期しない問題が発生してもスムーズに動作する堅牢なスクリプトを作成できます。その結果、不完全な操作、システム停止、またはデータ損失といった問題に悩まされることなく、自信を持ってタスクを自動化できます。
よくある質問
なぜ自分の PowerShell の try-catch はエラーをキャッチできないのですか?
try-catch ブロックが機能しない最も一般的な理由は、非終了(non-terminating)エラーを扱っているためです。PowerShell には、終了(terminating)エラー(実行を停止する)と、非終了(non-terminating)エラー(メッセージを表示するが処理は継続する)の2種類のエラーがあります。try-catch はデフォルトでは、終了(terminating)エラーのみをキャッチします。
非終端エラーをキャッチするには、try ブロック内のコマンドに -ErrorAction Stop を追加します。これにより、PowerShell がそのエラーを終端エラーとして扱うよう強制されます:
try {
Get-ChildItem "C:\NonExistent" -ErrorAction Stop
} catch {
Write-Host "Caught the error!"
}
-ErrorAction Stop がないと、エラーメッセージは表示されますが catch ブロックは一度も実行されません。
もう1つの問題はスコープ(範囲)に関するものです。try ブロック内から関数や外部スクリプトを呼び出している場合、それらから発生したエラーが正しくバブルアップ(上位へ伝播)されない可能性があります。呼び出している関数またはスクリプト側でも適切なエラー処理を使うようにするか、もしくは $ErrorActionPreference = "Stop" をスクリプトの先頭に記述して、デフォルト動作をグローバルに変更してください。グローバル設定の変更はスクリプト内のすべてのコマンドに影響するため、本番環境では慎重に使用してください。
PowerShell の try-catch を使っているのにエラーメッセージが表示され続けるのをどう直しますか?
適切に try-catch を実装していても、PowerShell が catch ブロックが処理する前にエラーメッセージを表示するため、依然としてエラーメッセージが見えることがあります。これは、次の -ErrorAction Stop を通じて終端エラーになる非終端エラーで起こります。エラーはコンソールに表示された後、ハンドラーによってキャッチされます。
エラー表示を完全に抑制するには、次を使用します。-ErrorAction SilentlyContinue そして $?(自動成功変数)または $Error[0] を確認して、直近のエラーを取得します。:
Get-ChildItem "C:\NonExistent" -ErrorAction SilentlyContinue
if (!$?) {
Write-Host "Command failed silently"
}
この方法により、見えるエラーメッセージを表示せずにエラー検出を制御できます。
よりすっきりした解決策として、catch ブロックでエラー情報を取得し、どのように扱うかを決めます。$_.Exception.Message を使用してエラーの詳細を取得し、その後必要に応じてログに記録するか表示します。こうすることで、ユーザーが見る内容を正確に制御できます:
try {
Get-ChildItem "C:\NonExistent" -ErrorAction Stop
} catch {
Write-Warning "Directory access failed: $($_.Exception.Message)"
}
このアプローチは、エラーメッセージをユーザーフレンドリーにし、適切にログへ記録する必要があるエンタープライズ環境で特に重要です。
非終端エラーが発生する場合、PowerShell の try-catch はどのように扱いますか?
非終了エラーは、デフォルトでは catch ブロックをトリガーしないため、特別な取り扱いが必要です。最も確実な方法は、エラーをキャッチしたい各コマンドに -ErrorAction Stop を使用することです。これにより、非終了エラーが try-catch で処理できる終了エラーに変換されます。
複数の非終了エラーを生成する関数では、関数レベルで $ErrorActionPreference = "Stop" を設定し、その後にリセットすることを検討してください:
function Test-Function {
$ErrorActionPreference = "Stop"
try {
# your commands here
} catch {
# error handling
} finally {
$ErrorActionPreference = "Continue"
}
}
代替の方法では -ErrorVariable パラメーターを使って、実行を停止せずにエラーを取得します。次のようにコマンドを実行してください: -ErrorVariable myErrors -ErrorAction SilentlyContinue その後 $myErrors に内容があるかどうか確認します。この方法なら、フローを中断せずにコマンド完了後にエラーを処理できます:
Get-ChildItem "C:\*" -ErrorVariable problems -ErrorAction SilentlyContinue
if ($problems) {
Write-Host "Found $($problems.Count) errors to review"
}
このパターンは、大量の処理で「対応方法を決める前にすべての問題を収集したい」場合にうまく機能します。
try-catch における ErrorAction Stop と SilentlyContinue の違いは何ですか?
ErrorAction Stop は、非終了エラーを終了エラーに変換し、実行を直ちに停止して catch ブロックをトリガーします。try-catch でエラーを処理したい場合、かつコマンドが失敗したら続行できない場合に使用してください。失敗したら処理を止めるべき重要な操作で、最も一般的な選択肢です。
ErrorAction SilentlyContinue はエラーメッセージを抑制し、実行を継続できるようにしますが、エラーは catch ブロックをトリガーしません。エラーは引き続き発生し、$Error に追加されます。ただし、画面に表示されるエラーメッセージは出ず、スクリプトは動き続けます。このオプションは、いくつかの処理が失敗することを想定していて、例外処理ではなく条件ロジックでそれらを扱いたい場合に役立ちます。
try-catch のシナリオで重要な違いは制御フローです。Stop を指定すると catch ブロックが実行され、次に何を行うかを決められます。SilentlyContinue を指定する場合は、$? 、 $Error 、または -ErrorVariable を使って、成功を手動で確認する必要があります。セキュリティ重視の操作では、Stop によってエラーの可視性と取り扱いがより良くなり、アクセス失敗やセキュリティ違反が見過ごされないことを保証します。エンタープライズ環境では、ErrorAction Stop を使った try-catch による明示的なエラーハンドリングにより、より良い監査ログ(監査証跡)と、より予測可能なスクリプト挙動が得られます。
PowerShell のループで try-catch を使い、実行を継続するにはどうすればよいですか?
ループ内では、try-catch の動作はエラーがどこで発生したか、そしてその後に何を起こしたいかによって変わります。エラーが発生しても残りの項目の処理を続けるには、try-catch をループの中に配置し、continue を catch ブロックで使います:
foreach ($item in $items) {
try {
Process-Item $item -ErrorAction Stop
} catch {
Write-Warning "Failed to process $item"
continue
}
}
これは失敗した項目をスキップして、次の項目に進みます。
失敗した操作を再試行したい場合は、try-catch と再試行カウンターを組み合わせてください:
foreach ($item in $items) {
$retries = 0
do {
try {
Process-Item $item -ErrorAction Stop
break
} catch {
$retries++
if ($retries -ge 3) {
Write-Error "Failed after 3 attempts: $item"
break
}
Start-Sleep 1
}
} while ($retries -lt 3)
}
このパターンは、ネットワーク操作や、一時的に失敗する可能性があるリソース集約型のタスクに有用です。
成功と失敗の両方を集めるには、配列を使って結果を追跡します:
$successful = @()
$failed = @()
foreach ($item in $items) {
try {
Process-Item $item -ErrorAction Stop
$successful += $item
} catch {
$failed += @{Item=$item; Error=$_.Exception.Message}
}
}
このアプローチはバルク(大量)操作に関する完全な可視性を提供します。これは、成功と失敗の両方を利害関係者に報告する必要があるデータ処理、ユーザー管理、またはシステム管理のタスクに不可欠です。
共有する
もっと詳しく
著者について
Tyler Reese
プロダクト マネジメント担当副社長、CISSP
ソフトウェア セキュリティ業界で20年以上の経験を持つ Tyler Reese は、今日の企業が直面している急速に変化するアイデンティティおよびセキュリティ上の課題について深く理解しています。現在、彼は Netwrix Identity and Access Management ポートフォリオのプロダクト ディレクターを務めており、市場動向の評価、IAM 製品ラインの方向性の設定、そして最終的にはエンド ユーザーのニーズに応えることが主な責任です。彼の専門的な経験は、Fortune 500 企業向けの IAM コンサルティングから、大手のダイレクト・トゥ・コンシューマー企業のエンタープライズ アーキテクトとしての業務まで多岐にわたります。現在、彼は CISSP の認定資格を保有しています。