書き込みエラーとスローのどちらを使用すればよいですか?終了エラーと非終了エラー


145

PoshCode(http://poshcode.org/3226)でGet-WebFileスクリプトを確認すると、この奇妙な仕掛けに気づきました。

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

以下とは対照的にこれの理由は何ですか?

$URL_Format_Error = [string]"..."
Throw $URL_Format_Error

またはさらに良い:

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

私が理解しているように、非終了エラーにはWrite-Errorを使用し、終了エラーにはThrowを使用する必要があるため、Write-Errorの後にReturnを使用しないでください。違いはありますか?


4
どういう意味ですか?Write_errorがスクリプトの続行を許可する場合、Write-Errorの後にreturnステートメントがあることは非常に理解できます。エラーが書き出され、最初に関数を呼び出したコードに戻ります。Throwはエラーを終了するためのものなので、throw宣言のreturnステートメントが役に立たないように自動的に終了します
Gisli

1
@ギスリ:(高度な)関数のブロックで呼び出し元に戻らないことに注意することreturnが重要です。代わりに、パイプラインの次の入力オブジェクトに進みます。実際、これは非終了エラーを生成するための典型的なシナリオです。さらに入力オブジェクトを処理することがまだ可能な場合。process
mklement0 2016

1
Throwは、スクリプトの終了エラーを生成することに注意してください。これは、またはによってトリガーされるステートメントの終了エラーとは異なります。Get-Item -NoSuchParameter1 / 0
mklement0 2017

回答:


188

Write-Error重要ではないエラーをユーザーに通知する場合に使用します。デフォルトでは、コンソールにエラーメッセージを赤いテキストで出力します。パイプラインやループの続行を停止することはありません。Throw一方、いわゆる終了エラーを生成します。throwを使用すると、パイプラインや現在のループが終了します。実際、trapまたはtry/catch構造体を使用して終了エラーを処理しない限り、すべての実行が終了します。

に設定$ErrorActionPreference"Stop"て使用Write-Errorすると、終了エラー発生することに注意してください

リンクしたスクリプトで次のことがわかります。

if ($url.Contains("http")) {
       $request = [System.Net.HttpWebRequest]::Create($url)
}
else {
       $URL_Format_Error = [string]"Connection protocol not specified. Recommended action: Try again using protocol (for example 'http://" + $url + "') instead. Function aborting..."
       Write-Error $URL_Format_Error
    return
   }

その関数の作成者は、その関数の実行を停止して画面にエラーメッセージを表示したかったが、スクリプト全体の実行を停止したくなかったようです。スクリプト作成者は使用できたかもしれthrowませんがtry/catch、関数を呼び出すときにaを使用する必要があることを意味します。

return関数、スクリプト、スクリプトブロックなどの現在のスコープを終了します。これはコードで最もよく示されています:

# A foreach loop.
foreach ( $i in  (1..10) ) { Write-Host $i ; if ($i -eq 5) { return } }

# A for loop.
for ($i = 1; $i -le 10; $i++) { Write-Host $i ; if ($i -eq 5) { return } }

両方の出力:

1
2
3
4
5

ここで一つ落とし穴が使用しているreturnForEach-Object。予想されるような処理を中断することはありません。

詳しくは:


OK、Throwはすべてを停止し、Write-Error + returnは現在の関数のみを停止します。
ビル・バリー

@BillBarry私はの説明で少し答えを更新しましたreturn
アンディアリスメンディ

OSに適切なエラーコードが返されるようにするために、write-Errorの後にexit(1)が続くのはどうですか それは適切ですか?
パブラム

19

主な違い書き込みエラーレットとスロー PowerShellのキーワードは、前者は単にことである印刷にいくつかのテキスト標準エラーストリーム(stderr)を後者は実際にしながら、終了された実行コマンドや関数の処理、次いで取り扱いをPowerShellを使用して、エラーに関する情報をコンソールに送信します。

提供した例では、2つの異なる動作を確認できます。

$URL_Format_Error = [string]"..."
Write-Error $URL_Format_Error
return

この例では、エラーメッセージがコンソールに送信された後にスクリプトの実行return明示的に停止するためにキーワードが追加されています。一方、2番目の例では、return終了が暗黙的に行われるため、キーワードは必要ありませんthrow

$URL_Format_Error = New-Object System.FormatException "..."
Throw $URL_Format_Error

2
$ ErrorActionPreference = "Stop"がある場合、Write-Errorもプロセスを終了します。
Michael Freidgeim 2017年

4
良い情報ですが、PowerShellのエラーストリームは、他のシェルのテキストベースの stderrストリームにていますが、すべてのPowerShellストリームと同様に、デフォルトで自動コレクションで収集されるオブジェクト、つまり[System.Management.Automation.ErrorRecord]インスタンスが含まれます$Error$Error[0]最新のエラーが含まれます)。あなただけ使用している場合でもWrite-Errorして、文字列、その文字列がに包まれます[System.Management.Automation.ErrorRecord]インスタンス。
mklement0 2017年

16

重要終了エラーに2種類ありますが、現在のヘルプトピックでは残念ながらこれらが混同されています。

  • ステートメント-終了できないエラー。特定の回復不可能な状況でコマンドレットによって報告され、.NET例外/ PSランタイムエラーが発生する式によって報告されます。ステートメントのみが終了し、スクリプトの実行はデフォルトで続行されます

  • error-action preference-variable / parameter valueを介して他のエラータイプのいずれかによってエスカレートされることによってトリガーされた、スクリプト終了エラー(より正確には runspace-terminating)。 キャッチされない限り、現在のランスペース(スレッド)を終了します。つまり、現在のスクリプトだけでなく、該当する場合はすべての呼び出し元も終了します。ThrowStop

PowerShellのエラー処理の包括的な概要については、このGitHubドキュメントの問題を参照してください。

この記事の残りの部分は、に焦点を当てて非終端文の終端エラー。


問題の核心に焦点を当てた既存の役に立つ答えを補完するために:どのようにしてください選択し、文を報告するかどうかを終端または非終了エラー

コマンドレットエラー報告には、役立つガイドラインが含まれています。実用的な要約を試してみましょう:

終了しないエラーの背後にある一般的な考え方は、大規模な入力セットの「フォールトトレラント」な処理を可能にすることです。入力オブジェクトのサブセットの処理に失敗しても、(デフォルトでは)長時間実行される可能性があるプロセス全体を中止しないでください。自動変数に収集されたエラーレコードを介して報告されるように、エラーを検査し失敗したオブジェクトのみを後で再処理できます$Error

  • コマンドレット/高度な機能の場合、NON-TERMINATINGエラーを報告します。

    • パイプライン入力および/または配列値パラメーターを介して、複数の入力オブジェクトを受け入れ、かつ
    • SPECIFIC入力オブジェクトエラーが発生し、かつ
    • これらのエラーは、原則としてさらに入力オブジェクトの処理を妨げません状況によっては、入力オブジェクトが残っていないか、以前の入力オブジェクトがすでに正常に処理されている可能性があります)。
      • 高度な関数では、を使用$PSCmdlet.WriteError()して非終了エラーを報告します(Write-Error残念ながら、呼び出し元のスコープで$?が設定されることはありません- このGitHubの問題を参照してください)。$False
      • 取り扱い終了しないエラーは:$?最新のコマンドが報告されたかどうかがわかります少なくとも一つの非終了エラーを。
        • したがって、ある$?という$Falseことは、入力オブジェクトの(空でない)サブセットが適切に処理されなかったことを意味します
        • 設定変数$ErrorActionPreferenceまたは共通のコマンドレットパラメーター、あるいはその両方-ErrorActionは、エラー出力の動作に関して非終了エラー(のみ)の動作と、非終了エラーをスクリプト終了エラーにエスカレーションするかどうかを変更できます。
  • その他すべての場合は、STATEMENT-TERMINATINGエラーを報告します。

    • 特に、SINGLEまたはNOの入力オブジェクトのみを受け入れ、NOまたはSINGLEの出力オブジェクトを出力するか、パラメーター入力のみを取得し、指定されたパラメーター値が意味のある操作を妨げるコマンドレット/高度な関数でエラーが発生した場合。
      • 高度な関数で$PSCmdlet.ThrowTerminatingError()は、ステートメント終了エラーを生成するためにを使用する必要があります。
      • 対照的に、Throwキーワードはスクリプト全体を中止するスクリプト終了エラーを生成することに注意してください(技術的には、現在のスレッド)。
      • 取り扱い:文の終了エラーtry/catchハンドラまたはtrap文が使用することができる(することができないで使用する非終了さえというエラー)が、ノートの文デフォルトでは、エラーを-terminatingが実行してから、スクリプトの残りを防ぐことはできません。同様に非終端エラー、$?反映$False前のステートメントは、ステートメントの終了エラーを引き起こした場合。

悲しいことに、PowerShellのコアコマンドレットのすべてがこれらのルールで機能するわけではありません

  • 失敗する可能性は低いですが、New-TemporaryFile(PSv5 +)は、パイプライン入力を受け入れず、出力オブジェクトを1つだけ生成するにもかかわらず、失敗した場合に非終了エラーを報告します-これは少なくともPowerShell [コア] 7.0以降で修正されていますが、このGitHubを参照してください問題

  • Resume-Jobのヘルプでは、サポートされていないジョブタイプ(で作成されたジョブなど、ワークフロージョブにのみ適用されるStart-Jobためサポートされていません)を渡すと終了エラーが発生すると主張していますが、PSv5.1以降では当てはまりません。Resume-Job


8

Write-Error関数のコンシューマがエラーメッセージを-ErrorAction SilentlyContinue(または-ea 0)で抑制できるようにします。一方でthrow必要となりますtry{...} catch {..}

try ... catchを使用するにはWrite-Error

try {
    SomeFunction -ErrorAction Stop
}
catch {
    DoSomething
}

エラーメッセージを抑制したいのに、なぜWrite-Errorを呼び出す必要があるのですか?
Michael Freidgeim 2017年

8

アンディアリスメンディの回答への追加:

Write-Error がプロセスを終了するかどうかは、$ErrorActionPreference設定によって異なります。

自明で$ErrorActionPreference = "Stop"はないスクリプトの場合、はすぐに失敗するための推奨設定です。

「エラーに関するPowerShellのデフォルトの動作。エラーが発生しても続行されます...非常にVB6の「On Error Resume Next」のような感じがします」

http://codebetter.com/jameskovacs/2010/02/25/the-exec-problem/から)

ただし、Write-Error通話が終了します。

使用するには書き込みエラーにかかわらず、他の環境設定の非終了コマンドとして、あなたは使用することができ、共通のパラメータを -ErrorAction値でContinue

 Write-Error "Error Message" -ErrorAction:Continue

0

コードの読み取りが正しい場合、あなたは正しいです。終了エラーはを使用する必要throwがあります。.NETタイプを処理している場合は、.NET例外規則にも従うと役立ちます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.