2013-07-25 29 views
11

この中でgreat article Keithは、Powershellの終了エラーと終了していないエラーの違いについて説明しています。 .NETオブジェクトまたはタイプのメンバーへの呼び出しからスローされるKeith例外によれば、非終了エラーです。その後、.netメソッドから例外として、終了または終了しないエラーがありますか?

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

そして、この機能を:我々はテストのために、この.NETクラスを定義する確かならば

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

我々はTST関数が呼び出されたときに例外が非ように見えることがわかります終了:第2のWrite-Hostが動作します。

しかし、これを考慮して

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

我々はthe documentationを開くと、我々はキャッチがに応答するか、スクリプトで終端エラーを処理することを読み取ることができます。記事の本文全体を通して、記事が扱っているエラーは、多くの場所で "終了"と認定されています。

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

どうしてですか?

別の観察は、古き良きトラップと、それはまだ終了しないエラーだということです。今

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

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

どうすればよいですか?

例:

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

私は上記の.NETの呼び出しからのすべての例外に終了させたいです。私はまた、コマンドレットからのエラーの終了時に終了したい。私は、コマンドレットからの終了していないエラーで終了したくありません。

+0

@keithhillお手伝いできますか?ありがとう! –

+0

これは$ ErrorActionPreferenceで定義できませんか?コードの実際の終了動作ではなく、スクリプトがそれをどのように処理するか... ...? –

答えて

9

ええ、これは今年初めにPowerShell MVPの電子メールリストに掲載されました。 PowerShellは、外部try/catchがあるかどうかによって.NET例外のエラー処理動作を変更します。これはちょうど投機ですが、私はこれが単純なスクリプトシナリオのためだと推測しています。つまり、scripter(admin)が.NETメソッドの呼び出しを邪魔して例外を生成した場合、PowerShellチームはスクリプト全体の実行を停止したくありませんでした。 V2が登場し、適切なtry/catchを導入すると、私は彼らがその決定を再検討しなければならないと推測し、現在の妥協案を思い付いた。

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

+0

もっと良い解決策があると思います。私の答えをチェックしてください。何か興味深いかもしれない。 – alecov

+0

@Alekあなたの解決策は、OPがtst2関数で実証したものと多かれ少なかれ、PowerShellは外部try/catchがあるかどうかに応じて.NET例外のエラー処理動作を変更します。 try/finally内のすべてのスクリプトをラップするモジュール内の多くの潜在的な関数を考えると、PITAです。ここでの実際のトリックは、行動を変更するグローバルな方法を見つけることです。 「その」トリックを見つけたら、教えてください。 ;-) –

1

は、いくつかのテストの後、例外が外try/catchブロックは、終端でも非終了エラーでもない独特のやり方で振る舞うを投げているようです。

は、次の出力を比較する:

# 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例外はない非終了エラー、または少なくともしないことによって生成されるエラーと同じ種類であることを示していますWrite-Error。一貫性のある結果を達成するために

、唯一の方法は、これまでcatchに例外であり、いずれかがthrowこと(終了エラーを生成する)またはWrite-Errorそれ(無終端エラーを作成する)に再。だから、

Try { Class::RunSomeCode() } Catch { Throw } 

あなたの例では、あなたのtst機能:あなたは、このようなブロックであなたの.NET呼び出しを囲むことができるようにTryブロックは、終了エラーに.NET例外をオン

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. 
+0

寄付いただきありがとうございますが、私のシナリオにどのように対処しているか分かりません。少し拡大していただけますか? –

+0

これは絶対に気にしないでください。あなたの質問は、スクリプト全体ではなく、特定のコード位置での.NET例外の管理方法に関するものだと思っていました。答えは、.NET例外をエラーを選択的に終了するように振る舞わせる方法を示しています。私はこの答えを他の人を助けることを望んでここに留めておきます。 – alecov

1

例えば:

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

.NET例外が終了するようになりました。

関連する問題