PowerShell エラーの詳細をログファイルに出力する
はじめに
最近、PowerShellでスクリプトをたまに書くことがあるが、エラー発生時に内容をログに記録させたい場合がある。
エラー原因が分かるレベルの必要な情報を出力するために、以外と簡単にできなかったので、調べたことをまとめる。
検証環境のバージョンは以下の通り。
- Windows 10
- PowerShell 5.0 (詳細は以下)
> $PSVersionTable Name Value ---- ----- PSVersion 5.0.10586.122 PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.10586.122 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
コンソールに表示されるエラーメッセージと同等の内容を取得する
基本は以下のように、エラーが発生する可能性のあるロジックをtry-catch構文で囲む。
$error
配列に発生したエラーが先頭に追加されるため、$error[0]
を参照することで
直前のtry文で発生したエラーオブジェクトが取得できる。
これをOut-String
を経由させることで、コンソールに表示されるエラーと同じ内容のテキストが得られる。
try { 1 / 0 } catch { $error[0] | Out-String | Out-File "error.log" }
得られるerror.logファイルは以下の通り。
0 で除算しようとしました。 発生場所 C:\dev\script.ps1:14 文字:5 + 1 / 0 + ~~~~~ + CategoryInfo : NotSpecified: (:) [], RuntimeException + FullyQualifiedErrorId : RuntimeException
コンソールに表示されるエラーメッセージと同等の内容がログファイルに出力される。
エラー内容の詳細を省略せずに取得する
単純なエラー内容であれば上で十分だが、PowerShellのコンソール出力されるログはCategoryInfo
の情報が長すぎると切れてしまう場合がある。
そのため、例えばファイルパスが長すぎる場合のエラーログを出力すると、どのようなファイルなのかという情報が得られないことがある。
以下は260文字以上のパスのフォルダを作成しているためにエラーが発生しているコードの例。
try { # 260文字以上のパスのフォルダ作成 $longDir = "C:\dev\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa \aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa" New-Item -Path $longDir -ItemType Directory } catch { $error[0] | Out-String | Out-File "error.log" }
得られるerror.logファイルは以下の通り。
New-Item : 指定されたパス、ファイル名、またはその両方が長すぎます。完全限定型名は 260 文字未満で指定し、ディレクトリ名は 248 未満で指定してください。 発生場所 C:\dev\script.ps1 :3 文字:5 + New-Item -Path $longDir -ItemType Directory + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : WriteError: (C:\dev\aaaaa\aa...aaa\aaaaa\aaaaa:String) [New-Item], PathTooLongException + FullyQualifiedErrorId : CreateDirectoryIOError,Microsoft.PowerShell.Commands.NewItemCommand
基本的なエラーメッセージなどは得られているが、CategoryInfo
の情報はよく見るとC:\dev\aaaaa\aa...aaa\aaaaa\aaaaa:String
となっており、
エラー原因の一部が...
と省略されてしまっていることが確認できる。
このことがエラーの原因究明に不都合な場合もあり、全文を表示させたい場合は以下のようにエラー出力ロジックを変更すると良い。
具体的には、Format-List
コマンドレットを用いてエラーオブジェクトの出力形式をリスト形式にする。
$error[0] | Format-List -force | Out-File "error.log"
この場合、得られるerror.logファイルは以下の通り。
Exception : System.IO.PathTooLongException: 指定されたパス、ファイル名、またはその両方が長すぎます。完全限定型名は 260 文字未満で指定し、ディレクトリ名は 248 未満で指定してください。 場所 System.IO.PathHelper.GetFullPathName() 場所 System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths) 場所 System.IO.Path.GetFullPathInternal(String path) 場所 System.IO.DirectoryInfo.Init(String path, Boolean checkHost) 場所 Microsoft.PowerShell.Commands.FileSystemProvider.CreateDirectory(String path, Boolean streamOutput) TargetObject : C:\dev\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaa a\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa\aaaaa CategoryInfo : WriteError: (C:\dev\aaaaa\aa...aaa\aaaaa\aaaaa:String) [New-Item], PathTooLongException FullyQualifiedErrorId : CreateDirectoryIOError,Microsoft.PowerShell.Commands.NewItemCommand ErrorDetails : InvocationInfo : System.Management.Automation.InvocationInfo ScriptStackTrace : <ScriptBlock>、C:\dev\script.ps1 : 行 3 PipelineIterationInfo : {} PSMessageDetails :
より詳細なエラー情報が得られ、先ほど省略されていた内容もTargetObject
という形で正しく表示されている。
まとめ
コンソールに出力されるエラー内容と同等のものをログに出力したい場合は
$error[0] | Out-String | Out-File "error.log"
を使う。
より詳細なエラーの情報を省略せずにログに出力したい場合は
$error[0] | Format-List -force | Out-File "error.log"
を使う。
以上