メモ。
違っている部分があればご指摘ください。
基本的には以下のMSの記事を参考に検証しているもで、こちらを確認頂いても良いかと思います。
An Introduction to Error Handling in PowerShell
環境
- PSVersion->5.0.10586.117
エラーメッセージをファイルに書き込みたい
リダイレクトについては以下に詳細がありました。
上記にもあるようにPowerShellではリダイレクト時に利用できるstreamが複数あります。
The Windows PowerShell redirection operators use the following characters
to represent each output type:
* All output
1 Success output
2 Errors
3 Warning messages
4 Verbose output
5 Debug messages
6 Informational messages
エラーは2です。
上記より、エラーをファイルに書き込む場合には以下のようにします。
command 2>error.txt
Bashなどでよく使うように標準出力及びエラーをファイルに追記する場合には以下のようにします。
command 2>&1 >> result.txt
実際にやってみます。
# 存在しないファイルを確認
PS C:\Users\Administrator> ls poyo.txt 2>>result.txt
PS C:\Users\Administrator> ls poyo.txt 2>>result.txt
# catコマンドをファイルにエラーメッセージが書き込まれるかを確認
PS C:\Users\Administrator> cat .\result.txt
ls : Cannot find path 'C:\Users\Administrator\poyo.txt' because it does not exist.
At line:1 char:1
+ ls poyo.txt 2>>result.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\poyo.txt:String) [Get-ChildItem], ItemNotFoundEx
ception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
ls : Cannot find path 'C:\Users\Administrator\poyo.txt' because it does not exist.
At line:1 char:1
+ ls poyo.txt 2>>result.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\poyo.txt:String) [Get-ChildItem], ItemNotFoundEx
ception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
次にPowerShellコマンドを作成して、標準出力と標準エラー出力の確認をしてみます。
# 空のファイルを作成
PS C:\Users\Administrator> New-Item errorTest.ps1 -type file
Directory: C:\Users\Administrator
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/5/2016 1:15 AM 0 errorTest.ps1
# ファイルを開く
PS C:\Users\Administrator> Invoke-Item .\errorTest.ps1
Get-Date
ls poyo.txt
実行してみます。
# 実行。標準出力と標準エラー出力をresult.txtに追記
PS C:\Users\Administrator> powershell.exe .\errorTest.ps1 2>&1 >> result.txt
# 確認。標準出力及び標準エラー出力が確認できる
PS C:\Users\Administrator> cat .\result.txt
Wednesday, October 5, 2016 1:19:28 AM
powershell.exe : ls : Cannot find path 'C:\Users\Administrator\poyo.txt' because it does not exist.
At line:1 char:1
+ powershell.exe .\errorTest.ps1 2>&1 >> result.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (ls : Cannot fin...does not exist.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
At C:\Users\Administrator\errorTest.ps1:2 char:1
+ ls poyo.txt
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\poyo.txt:String) [Get-ChildItem], ItemNotFoundEx
ception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
$error変数について
An Introduction to Error Handling in PowerShell
PowerShellでエラーが発生した場合、$errorというArrayListに情報が追加されます。
直近のエラーは$error[0]に格納されます。
# 存在しないコマンドを実行
PS C:\Users\Administrator> hogefuga
hogefuga : The term 'hogefuga' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ hogefuga
+ ~~~~~~~~
+ CategoryInfo : ObjectNotFound: (hogefuga:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
# 最新のエラー情報を確認
PS C:\Users\Administrator> $error[0]
hogefuga : The term 'hogefuga' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ hogefuga
+ ~~~~~~~~
+ CategoryInfo : ObjectNotFound: (hogefuga:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
$errorのArryListのそれぞれはErrorRecordになっています。
get-member(Alias gm)でメンバー情報を確認してみます。
PS C:\Users\Administrator> $error[0] | gm
TypeName: System.Management.Automation.ErrorRecord
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System....
GetType Method type GetType()
ToString Method string ToString()
CategoryInfo Property System.Management.Automation.ErrorCategoryInfo CategoryInfo {get;}
ErrorDetails Property System.Management.Automation.ErrorDetails ErrorDetails {get;set;}
Exception Property System.Exception Exception {get;}
FullyQualifiedErrorId Property string FullyQualifiedErrorId {get;}
InvocationInfo Property System.Management.Automation.InvocationInfo InvocationInfo {get;}
PipelineIterationInfo Property System.Collections.ObjectModel.ReadOnlyCollection[int] PipelineIterationInfo {g...
ScriptStackTrace Property string ScriptStackTrace {get;}
TargetObject Property System.Object TargetObject {get;}
PSMessageDetails ScriptProperty System.Object PSMessageDetails {get=& { Set-StrictMode -Version 1; $this.Except...
ErrorRecordの詳細はこちら
個別に取得したい場合にはException
やInvocationInfo
を使っても良いでしょうし、とりあえず全部出力したい場合にはOut-String
を使って画面の出力を文字列にして表示しても良いと思われます。
上記は以下のStackOverflowの記事が参考になりました。
How can I get powershell exception descriptions into a string?
# Out-Stringで文字列を取得
PS C:\Users\Administrator> $error[0] | Out-String
hogefuga : The term 'hogefuga' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ hogefuga
+ ~~~~~~~~
+ CategoryInfo : ObjectNotFound: (hogefuga:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
# Exception
PS C:\Users\Administrator> $error[0].Exception
The term 'hogefuga' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
# InvocationInfo
PS C:\Users\Administrator> $error[0].InvocationInfo
MyCommand :
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 1
OffsetInLine : 1
HistoryId : 3
ScriptName :
Line : hogefuga
PositionMessage : At line:1 char:1
+ hogefuga
+ ~~~~~~~~
PSScriptRoot :
PSCommandPath :
InvocationName : hogefuga
PipelineLength : 0
PipelinePosition : 0
ExpectingInput : False
CommandOrigin : Internal
DisplayScriptPosition :
Error Action Preferenceについて
An Introduction to Error Handling in PowerShell
PowerShellのスクリプトででエラーが発生した場合にそのまま処理を継続したり、終了させたりすることができます。
設定できるものとして以下があり、デフォルトはエラーが発生してもエラーを出力し、そのままスクリプトを継続するようになっています。
- Stop:エラー メッセージが表示され、実行が停止されます。
- Inquire:エラー メッセージが表示され、続行するかどうかを確認するメッセージが表示されます。
- Continue (既定値):エラー メッセージが表示され、実行が続行されます。
- Suspend:さらなる調査のため、ワークフロー ジョブを自動的に中断します。調査の後で、ワークフローを再開できます。
- SilentlyContinue:影響を与えません。エラー メッセージは表示されず、中断されることなく実行が続行されます。
# 同じセッションの場合の挙動を変更。PowerShellを別途起動した場合にはデフォルト値に戻る
PS C:\Users\Administrator> $ErrorActionPreference
Continue
PS C:\Users\Administrator> $ErrorActionPreference = "Stop"
PS C:\Users\Administrator> $ErrorActionPreference
Stop
スクリプト内でも上記設定を変更することで挙動の変更が可能です。
以下を実行すると2行目でエラーとなるため、stopし、Get-Date
は実行されません。
$ErrorActionPreference = "Stop"
ls poyo.txt
Get-Date
こちらは$ErrorActionPreferenceの値がデフォルトのContinueのため、エラーが発生しても継続して処理を行うためGet-Date
が実行されます。
ls poyo.txt
Get-Date
なお、実行するコマンドレット単位でも-ErrorActionオプションを付与することでコマンドごとの挙動を変更することも可能です。
こちらの記事も読んでおくと良い。
Understanding Non-Terminating Errors in PowerShell
Try/Catch/Finally ブロックについて
An Introduction to Error Handling in PowerShell
Javaとかにもあるtry/catch/finallyとかがPowerShellのスクリプトでも書けて、Exception発生時の処理をcatch構文に書いておくことでエラー時の処理を書けるよというような話。’
同じようにfinallyでconnectionのクローズをするとかもできそうです。
なお、リンクにもあるようにコマンドレットの例外を補足するには対象のコマンドレットで-ErrorAction stop
オプションを指定する必要があります。
例えば以下ではcatch以降は呼びされません。
try{
ls poyo.txt
} catch {
Write-Output "catch error"
}
PS C:\Users\Administrator> powershell.exe .\ngtrycatch.ps1
ls : Cannot find path 'C:\Users\Administrator\poyo.txt' because it does not exist.
At C:\Users\Administrator\trycatch.ps1:2 char:3
+ ls poyo.txt
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\poyo.txt:String) [Get-ChildItem], ItemNotFoundEx
ception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
以下のようにすることでエラーを発生させず、処理の対応が可能。
try{
ls poyo.txt -ErrorAction stop
} catch {
Write-Output "catch error"
}
PS C:\Users\Administrator> powershell.exe .\trycatch.ps1
catch error
$errorを使うとcatchした時にエラーを標準出力に記載したりもできる。(そもそもエラーはエラー出力に出すべきというのは理解しつつ)
try{
ls poyo.txt -ErrorAction stop
} catch {
Write-Output "catch error"
Write-Output $error[0]
}
PS C:\Users\Administrator> powershell.exe .\trycatchwitherror.ps1
catch error
ls : Cannot find path 'C:\Users\Administrator\poyo.txt' because it does not exist.
At C:\Users\Administrator\trycatch.ps1:2 char:3
+ ls poyo.txt -ErrorAction stop
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\Administrator\poyo.txt:String) [Get-ChildItem], ItemNotFoundEx
ception
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Out-String
と組み合わせてStringで取得し、独自のログに書くなどもできそうです。