13

この素晴らしい記事で、Keith は Powershell の終了エラーと非終了エラーの違いについて説明しています。Keith によると、.NET オブジェクトまたは型のメンバーへの呼び出しからスローされる例外は非終了エラーです。

実際、テスト用にこの .NET クラスを定義すると、次のようになります。

$a = Add-Type 'public class bla { public static void bl() { throw new System.ApplicationException("test"); }}' -PassThru

そして、この関数:

function tst { 1 | write-host; $a::bl(); 2 | Write-host }

tst 関数が呼び出されると、例外が終了しないように見えることがわかります。2 番目の関数は機能しますWrite-Host

しかし、これを考慮してください:

function tst2 { try { tst } catch { "Catch!" } }

ドキュメントを開くと、キャッチがスクリプトの終了エラーに応答または処理することがわかります。記事のテキスト全体を通して、記事が扱っているエラーは、多くの場所で「終了」と見なされます。

したがって、上の行を実行すると、2 番目の Write-Host は実行されませんが、catch ブロックは実行されます。未終了エラーが突然終了するようです。

どうして?

もう 1 つの観察結果は、古き良きトラップではまだ終了しないエラーであるということです。

function tst3 { tst trap { "Trap!" } }

さて、実用的な観点から、私が達成したいことは次のとおりです。コードのブロックで、.NET コードからスローされた例外で終了したいと考えています。コマンドレットの終了エラーからの終了エラーと、コマンドレットの非終了エラーからの非終了エラーを残したいです。

どうすればこれを達成できますか?

例:

Do-Something
Call::Something()
Do-SomethingElse
Call::SomethingElse()
Do-YetMoreSomething
Call::YetMoreSomething()

上記の .NET 呼び出しからのすべての例外で終了したいと考えています。また、コマンドレットからの終了エラーで終了したいと考えています。コマンドレットからの非終了エラーで終了したくありません。

4

4 に答える 4

11

ええ、これは今年初めに PowerShell MVP メーリング リストに掲載されました。PowerShell は、外部の try/catch があるかどうかに応じて、.NET 例外のエラー処理動作を変更します。これは憶測にすぎませんが、これは単純なスクリプト シナリオ用だったと思います。つまり、スクリプト作成者 (管理者) が .NET メソッドの呼び出しに失敗して例外が生成された場合、PowerShell チームは、それによってスクリプト全体の実行が停止されることを望んでいませんでした。V2 が登場し、適切な try/catch が導入された後、彼らはその決定を再検討し、現在の妥協点を考え出す必要があったと思います。

とはいえ、これを回避することは、あなたが発見したように苦痛です。Stopスクリプト レベルで$ErrorActionPreference を設定し、終了しないエラーを生成する可能性のあるすべてのコマンドレットに対して、-ErrorAction Continueパラメーターを使用できます。または、すべての .NET 呼び出しを高度な関数内に配置し、その関数をパラメーターで呼び出すことができます-ErrorAction Stop。より良い答えがあればいいのですが、その MVP スレッドを確認した後、より良い解決策が見つかりませんでした。

于 2013-07-25T04:56:19.807 に答える
1

いくつかのテストの後、/ブロックの外側で スローされた例外は、終了エラーでも非終了エラーでもない独特の方法で動作するようです。trycatch

次の出力を比較します。

# Functions which create simple non-terminating errors.
function E1 { [CmdletBinding()] param() Write-Error "Error"; "E1" }
function E2 { [CmdletBinding()] param() Write-Error "Error" -ErrorAction:Stop; "E2" }

# Functions which throw .NET exceptions, inside and outside try/catch blocks.
function F1 { [CmdletBinding()] param() [DateTime]""; "F1" }
function F2 { [CmdletBinding()] param() try { [DateTime]"" } catch { throw } "F2" }

# Test functions.
function TestE1 { [CmdletBinding()] param() E1; "TestE1" }
function TestF1 { [CmdletBinding()] param() F1; "TestF1" }
function TestE2 { [CmdletBinding()] param() E2; "TestE2" }
function TestF2 { [CmdletBinding()] param() F2; "TestF2" }
function StopE1 { [CmdletBinding()] param() E1 -ErrorAction:Stop; "StopE1" }
function StopF1 { [CmdletBinding()] param() F1 -ErrorAction:Stop; "StopF1" }
function StopE2 { [CmdletBinding()] param() E2 -ErrorAction:Stop; "StopE2" }
function StopF2 { [CmdletBinding()] param() F2 -ErrorAction:Stop; "StopF2" }

# All the following call pairs display similar behavior.
TestE1        # Returns "E1", "TestE1".
TestF1        # Returns "F1", "TestF1".

TestE2        # Halts and returns nothing.
TestF2        # Halts and returns nothing.

StopE2        # Halts and returns nothing.
StopF2        # Halts and returns nothing.

# The following display different behavior.
StopE1        # Halts and returns nothing.
StopF1        # F1 halts but StopF1 doesn't; the call returns "StopF1".

tryこれは、 /catchブロックの外側でスローされた .NET 例外が非終了エラーではないこと、または .NET によって生成されるエラーと少なくとも同じ種類ではないことを示していますWrite-Error

一貫した結果を得るには、これまでの唯一の方法はcatch、例外に対して、re throw(終了エラーを作成する) またはWrite-Errorそれ (非終了エラーを作成) することです。例えば:

function F1 { [CmdletBinding()] param() try { [DateTime]"" } catch { Write-Error -ErrorRecord:$_ } "F1" }

# Now everything's fine.
TestE1        # Returns "E1", "TestE1".
TestF1        # Returns "F1", "TestF1".

StopE1        # Halts and returns nothing.
StopF1        # Halts and returns nothing.
于 2014-02-01T19:03:31.120 に答える