エラー処理

完了

ここまでは、パラメーターとフロー制御コンストラクトを追加して、スクリプトの柔軟性を高め、より安全に使用できるようにする方法について説明しました。 ただし、スクリプトでエラーが発生することがあります。 これらのエラーを処理する方法が必要です。

次に、考慮すべき点をいくつか示します。

  • エラーを処理する方法。 回復可能なエラーが発生することもあり、スクリプトを停止したほうがよいこともあります。 発生する可能性があるエラーの種類と、それらを最も適切に管理する方法を検討することが重要です。

  • エラーの重大度。 エラー メッセージにはさまざまな種類があります。 あるものは、大丈夫ではないものがあることをユーザーに知らせる警告に似ています。 あるものは重大度が高く、ユーザーが本当に注意を払う必要があります。 エラー処理のアプローチは、エラーの種類によって異なります。 このアプローチとしては、メッセージを表示することから、重大度レベルを上げ、おそらくスクリプトを停止することまでさまざまに考えられます。

エラー

たとえば、コマンドレットまたは関数によりさまざまな種類のエラーが生成される可能性があります。 発生する可能性があるそれぞれの種類のエラーを管理するコードを記述し、種類が指定されたら適切にエラーを管理することをお勧めします。 たとえば、ファイルに書き込もうとしているとします。 問題によっては、さまざまな種類のエラーが発生する可能性があります。 ファイルへの書き込みが許可されていない場合、ある種類のエラーが発生します。 ファイルが存在しない場合は、別の種類のエラーが発生します。

PowerShell を実行するときに表示される可能性があるエラーには、次の 2 種類があります。

  • 終了エラー。 この種類のエラーの場合、エラーが発生した行で実行が停止します。 この種類のエラーは、Try-Catch または Trap を使用して処理できます。 エラーが処理されない場合、スクリプトはその時点で終了し、ステートメントは実行されません。

    Note

    Trap コンストラクトについては、このモジュールでは扱いません。 関心がある場合は、「トラップについて」を参照してください。

  • 終了しないエラー。 この種類のエラーでは、問題が発生したことをユーザーに通知しますが、スクリプトは続行されます。 この種類のエラーを終了エラーにアップグレードできます。

Try/Catch/Finally を使用したエラーの管理

終了エラーは予期しないエラーと見なすことができます。 これらのエラーは重大です。 対処する際には、エラーの種類とその対処法を考慮する必要があります。

この種類のエラーの管理に役立つ 3 つの関連するコンストラクトがあります。

  • TryTry ブロックを使用して、1 つ以上のステートメントをカプセル化します。 実行するコード (たとえばデータ ソースに書き込むコード) を中かっこ内に置きます。 Try には少なくとも 1 つの Catch または Finally ブロックが必要です。 しくみは次のとおりです。

    Try {
       # Statement. For example, call a command.
       # Another statement. For example, assign a variable.
    }
    
  • Catch。 このキーワードを使用して、発生時にエラーをキャッチまたは管理します。 次に、例外オブジェクトを調べて、発生したエラーの種類、発生した場所、スクリプトを回復できるかどうかを把握します。 CatchTry の直後に続きます。 必要に応じて、1 つ以上の Catch (エラーの種類ごとに 1 つ) を含めることができます。 次に例を示します。

    Try {
       # Do something with a file.
    } Catch [System.IO.IOException] {
       Write-Host "Something went wrong"
    }  Catch {
       # Catch all. It's not an IOException but something else.
    }
    

    このスクリプトでは、一部の I/O 処理を行うコマンドの実行を試みます。 最初の Catch では、特定の種類のエラー ([System.IO.IOException]) をキャッチします。 最後の Catch では、[System.IO.IOException] でないものをすべてキャッチします。

  • Finally。 このブロック内のステートメントは、問題が発生したかどうかに関係なく実行されます。 このブロックを使用することはあまりないと思われますが、たとえばリソースをクリーンアップする場合に便利です。 これを使用するには、最後のブロックとして追加します。

    Try {
       # Do something with a file.
    } Catch [System.IO.IOException] {
       Write-Host "Something went wrong"
    }  Catch {
       # Catch all. It's not an IOException but something else.
    } Finally {
       # Clean up resources.
    }
    

エラーの検査

例外オブジェクトについては、エラーをキャッチするコンテキストで説明しました。 これらのオブジェクトを使用して、問題の原因を調査し、適切な対策を講じることができます。 例外オブジェクトには次のものが含まれます。

  • メッセージ。 メッセージには、どのような問題が発生したかが手短に示されます。

  • スタックトレース。 スタックトレースには、エラーの前に実行されたステートメントが示されます。 たとえば、関数 A を呼び出した後に、B、C の順に呼び出したとします。このスクリプトは C で応答を停止します。スタックトレースにはこの一連の呼び出しが示されます。

  • 問題のある行。 また、例外オブジェクトには、エラーが発生したときにスクリプトで実行されていた行が示されます。 この情報はコードのデバッグに役立ちます。

それでは、例外オブジェクトを検査するにはどうすればよいでしょうか。 exception プロパティを伴う組み込み変数 $_ があります。 たとえば、エラー メッセージを取得するには、$_.exception.message を使用します。 コードでは次のようになります。

Try {
     # Do something with a file.
   } Catch [System.IO.IOException] {
     Write-Host "Something IO went wrong: $($_.exception.message)"
   }  Catch {
     Write-Host "Something else went wrong: $($_.exception.message)"
   }

エラーの発生

状況によっては、次のようなエラーを発生させる必要があります。

  • 終了しないエラー。 この種類のエラーの場合、PowerShell では、たとえば Write-Error コマンドレットを使用して、問題が発生したことを通知するだけです。 スクリプトは引き続き実行されます。 これは望みの動作ではないことがあります。 エラーの重大度を上げるには、-ErrorAction のようなパラメーターを使用して、次のように Try/Catch でキャッチできるエラーを発生させます。

    Try {
       Get-Content './file.txt' -ErrorAction Stop
    } Catch {
       Write-Error "File can't be found"
    }
    

    -ErrorAction パラメーターと値 Stop を使用すると、Try/Catch でキャッチできるエラーを発生させることができます。

  • ビジネス ルール。 実際にはコードが応答を停止しないが、ビジネス上の理由から停止させる必要のある状況があります。 たとえば、入力をサニタイズし、パラメーターがパスであるかどうかを確認するとします。 ビジネス要件では、特定のパスのみが許可されるということや、特定の方法でパスを表示する必要があるということを指定できます。 チェックが失敗した場合に、エラーをスローすることは理にかなっています。 次のような状況では、Throw ブロックを使用できます。

    Try {
       If ($Path -eq './forbidden') 
       {
         Throw "Path not allowed"
       }
       # Carry on.
    
    } Catch {
       Write-Error "$($_.exception.message)" # Path not allowed.
    }
    
    

    Note

    一般に、パラメーターの検証には Throw を使用しないでください。 代わりに、検証属性を使用してください。 コードでこれらの属性を扱えるようにすることができない場合は、おそらく Throw で問題ありません。