PowerShell捕獲エラーについて話します。


前の記事ではWindows PowerShellを使ってかなり高級なリストツールを構築する方法を実証しました。私が作成したツールは、外部の内蔵機能と関数をオブジェクトに適用するための出力に関するオプションを複数提供しています。
作成した関数には否定できない弱点があります。接続や権限などの問題を適切に処理できません。これは今期のWindows PowerShellのコラムで解決したいと思います。Windows PowerShellが提供しているエラー処理機能を紹介します。
Trapを設定
Windows PowerShellでは、Trapキーワードはエラー処理プログラムを定義します。スクリプトに異常がある場合、Trapが定義されているかどうかを確認します。これはスクリプトに異常が発生する前に必ず現れるということです。本デモンストレーションについては、接続性の問題が発生するテストスクリプトを整理します。Get-WmiObject接続ネットワークには存在しないコンピュータ名を使用します。エラーTrapが無効なコンピュータ名をファイルに書き出すことを目標にしています。無効なコンピュータ名を記録したファイルを提供してください。私はまた、2つの効果的なコンピュータの接続に参加します。図1のスクリプトを参照してください。
Trapを追加

trap {
 write-host "Error connecting to $computer" -fore red
 "$computer" | out-file c:\demo\errors.txt -append 
 continue
}

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer 

$computer = "server2"
get-wmiobject win32_operatingsystem -comp $computer 

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer

このスクリプトの出力(図2に示すように)は私の期待に合わないです。「Err connecting to」メッセージは表示されません。Errers.txtファイルも作成されていません。つまり、私のTrapは実行されていません。いったい何が起こったのですか?

図2これは私の希望の出力ではありません。
やめて!
鍵は正常なエンクロージャエラーメッセージが異常と異なることを知ることである(非終了エラーと終了エラーに分けられる。エラーが終了すると配管の実行を停止し、異常が発生します)。異常だけが捕獲される。エラーが発生した場合、エンクロージャは内蔵されているErrarAction Preference変数を確認して、自分の実行する操作を確定します。デフォルトでは「Continue」の値が含まれています。これは「エラーメッセージを表示して続行する」という意味です。この変数を「Stop」に変更するとエラーメッセージが表示され、捕獲可能な異常が発生します。しかし、これはあなたのスクリプトのどのエラーも実行されることを意味します。
より良い方法は、問題を引き起こす可能性があると考えられるcmdletに「停止」を使うことです。この動作は、CErrorAction(またはCEA)パラメータ(すべてのcmdletでサポートされている共通のパラメータ)を使用して行われてもよい。図3はこのスクリプトのリビジョンを示しています。これは、図4に示すように、意図的に動作します。
 使用-Errorアクション

trap {
 write-host "Error connecting to $computer" -fore red
  "$computer" | out-file c:\demo\errors.txt -append 
 continue
}

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer -ea stop

$computer = "server2"
get-wmiobject win32_operatingsystem -comp $computer -ea stop

$computer = "localhost"
get-wmiobject win32_operatingsystem -comp $computer -ea stop


【図4】CErrorActionパラメータを使用する場合、より多くの有用な結果を得た。
Trapの最後にContinueを使用して、異常なコードラインが発生した後のラインをカバーに実行し続けるように指示します。キーワードBreakも使えます。また、Trap内では、$コンピュータ変数(スクリプトで定義)が有効です。Trapはシナリオ自体のサブスコープであり、Trapはシナリオ内のすべての変数を見ることができるからです。
スコープですべての操作を完了します。
Windows PowerShellの中でエラー捕獲の一つが特に苦手なのは、ドメインの使用です。外筐自体は大域作用域を表し、外筐内部で発生する全ての事象を含んでいる。スクリプトを実行すると、スクリプトのスコープが取得されます。関数を定義すると、その内部は自分の専用のスコープなどです。これは親/サブタイプの階層構造を作成します。
異常が発生した場合、ケーシングは現在のスコープ内でTrapを検索します。これは、ある関数内の異常がこの関数の内部でTrapを検索することを意味する。ケースがTrapを発見したらTrapを実行します。TrapがContinueで終わると、カバーは異常を引き起こすコードラインの後ろの行を実行し続けますが、同じスコープにあります。以下では、この点を一部の疑似コードによって説明する。

Trap {
 # Log error to a file
 Continue
}
Get-WmiObject Win32_Service Ccomp "Server2" Cea "Stop"
Get-Process
異常が5行目に発生すると、1行目のTrapが実行されます。TrapはContinueで終わるので、6行目を実行し続けます。
以下のこのやや異なる作用領域の例を考える。

 Trap {
  # Log error to a file
  Continue
 }
 
 Function MyFunction {
  Get-WmiObject Win32_Service Ccomp "Server2" Cea "Stop"
  Get-Process
 }
 
 MyFunction
 Write-Host "Testing!"
エラーが7行目に発生した場合、カバーは関数のスコープ内でTrapを検索します。見つかっていない場合、外側は関数のスコープを脱退し、親のスコープ内でTrapを検索し続ける。そこにTrapがありますので、1行目を実行します。本例では、コードはContinueであるため、8行目ではなく、同じスコープ内の異常後のコードライン、すなわち12行目を実行し続ける。換言すれば、エンクロージャは終了後、再びこの関数に入ることはない。
この挙動を以下の例と比較します。

Function MyFunction {
 Trap {
  # Log error to a file
  Continue
 }
 Get-WmiObject Win32_Service Ccomp "Server2" Cea "Stop"
 Get-Process
}
 
MyFunction
Write-Host "Testing!"
本例では、6行目のエラーは2行目のTrapを実行し、関数のスコープ内に保持します。Continueキーワードはこの機能領域に保持され、7行目の実行を継続します。予期していたエラーが発生すると予想されるスコープにTrapを入れた場合、あなたはまだスコープに留まり、実行を継続することができます。この方法があなたの状況に適用されない場合はどうすればいいですか?
このツールは構成ベースラインを管理するのに非常に適しています。Compre-Object(またはDiff)は2つのグループのオブジェクトを比較することを目的としている。デフォルトでは、各オブジェクトの属性をすべて比較し、そのコマンドによってすべての違いを出力します。ですから、あるサーバーのサービスを完全にあなたの要求通りに設定したと思います。下の内容を実行するだけでベースラインを作成できます。

Get-Service | Export-CliXML c:\baseline.xml
ほとんどのオブジェクトは、Export CliXMLに送られ、オブジェクトをXMLファイルに変換します。その後、同じコマンドを実行して、結果を保存されたXMLと比較することができます。コマンドは以下の通りです

Compare-Object (Get-Service) (Import-CliXML 
 c:\baseline.xml) Cproperty name
Cpropertyパラメータを追加すると、オブジェクト全体ではなく属性のみを見ることができます。この例では、オリジナルのベースラインとは異なるすべてのサービス名からなるリストを取得します。作成後のベースラインにサービスが追加されているかどうか、または削除されているかを確認してください。
切断
前にBreakのキーワードを言ったことがあります。【図5】Breakキーの使い方の例を示す図である。
Breakキーワードを使う

 Trap {
  # Handle the error
  Continue
 }
 
 Function MyFunction {
  Trap {
   # Log error to a file
   If ($condition) {
    Continue
   } Else {
    Break
   }
  }
  Get-WmiObject Win32_Service Ccomp "Server2" Cea "Stop"
  Get-Process
 }
 
 MyFunction
 Write-Host "Testing!"
以下では、実行チェーンについて簡単に説明します。まず19行目を実行します。6行目の関数を呼び出します。15行目を実行して異常が発生します。この異常は7行目で捕獲され、Trapは9行目で決定しなければなりません。ドルconditionがTrueであると仮定して、Trapは16行目で実行します。
しかし、もし$conditionがFalseであれば、Trapは中断されます。これは現在のスコープを終了し、元の異常を親に伝えます。筐体から見て、19行目に異常が生じ、1行目に捕獲されることを意味する。Continueキーワードは強制的にエンクロージャを20行目に実行します。
実際には、この二つのTrapには、エラーを処理したり、記録したりするためのコードがいくつか含まれています。この例では、この関数コードを省略しただけで、実際の流れをより見やすくします。
なぜ心配ですか?
いつエラーを捕まえますか?2つの場合:予測はエラーが発生する可能性があり、通常のエラーメッセージを超えたい場合(例えばエラーをファイルに記録したり、より有益なエラーメッセージを表示したりする)。
通常は複雑なシナリオの中にエラー処理を入れて、発生したエラーを予測できるように処理します。これらのエラーは接続不良や権限問題などのエラーを含むが、これらに限らない。
間違いの捕獲には多くの時間と精力が必要です。Windows PowerShellでより複雑なタスクを処理するには、エラーキャプチャを実施して、より完璧で専門的なツールを構築する必要があります。