PowerShellでは色々な方法があるログメッセージの残し方を幾つか紹介します。
※ PowerShell 6.1を使用します。
以下のようなサンプルを用意しました。関数を作ると楽です。
=====<Logging.ps1>=====
# LogMessage関数を作成。
function LogMessage($Message){
Write-Output "$(Get-Date -Format G): $Message"
}
LogMessage "スクリプトを開始したよ(*´ー`*)"
# ここでメインの処理を実行。サンプルは5秒待機を5回。
for ($i=1; $i -le 5; $i++){
Start-Sleep 5
LogMessage "$i 番目の処理が完了したよ(*´ー`*)"
}
LogMessage "全ての処理が完了したよ(*´ー`*)"
LogMessage "スクリプトを終了するよ(*´ー`*)"
=====<Logging.ps1>=====
Write-Outputはコマンドプロンプトで言うechoに相当し、PowerShellでは「echo」がWrite-Outputのエイリアスとして使用できます。
このスクリプトを実行したときの出力は以下のようになります。
これだけでは画面への出力しか行われませんので、更にファイルへの出力を考えていきます。
■Start/Stop-Transcriptの使用
スクリプトを以下のように改修します。(赤字が変更点)
=====<Logging-Transcript.ps1>=====
# ログ出力先
$logFile = $PSScriptRoot + "\log\logfile.txt"
# LogMessage関数を作成。
function LogMessage($Message){
Write-Output "$(Get-Date -Format G): $Message"
}
Start-Transcript -Path $logFile -Append
LogMessage "スクリプトを開始したよ(*´ー`*)"
# ここでメインの処理を実行。サンプルは5秒待機を5回。
for ($i=1; $i -le 5; $i++){
Start-Sleep 5
LogMessage "$i 番目の処理が完了したよ(*´ー`*)"
}
LogMessage "全ての処理が完了したよ(*´ー`*)"
LogMessage "スクリプトを終了するよ(*´ー`*)"
Stop-Transcript
=====<Logging-Transcript.ps1>=====
このスクリプトの出力結果とファイルの中身は以下のようになります。
ご覧のようにTranscriptは記述が簡単ですが、情報量が多く不要なものまで追記の度に書き込まれるため視認性が悪くなりがち。
また、エンコードの指定が出来ません。
Transcriptは直接コンソール上で作業するログを残すには有用です。
■リダイレクト演算子(>/>>)の使用
=====<Logging-Redirect.ps1>=====
# ログ出力先
$logFile = $PSScriptRoot + "\log\logfile.txt"
# LogMessage関数を作成。
function LogMessage($Message){
$msg = "$(Get-Date -Format G): $Message"
Write-Output $msg
$msg >> $logFile
}
LogMessage "スクリプトを開始したよ(*´ー`*)"
(中略)
LogMessage "スクリプトを終了するよ(*´ー`*)"
==<Logging-Redirect.ps1>=====
出力結果とファイルは以下のようになります。
リダイレクト演算子もエンコードの指定が出来ません。
■Add(Set)-Contentの使用
※これ以降紹介するスクリプトは全てリダイレクト演算子を用いた場合と同様の出力結果となります。
=====<Logging-AddContent.ps1>=====
# ログ出力先
$logFile = $PSScriptRoot + "\log\logfile.txt"
# LogMessage関数を作成
function LogMessage($Message){
Write-Output "$(Get-Date -Format G): $Message" `
|Add-Content -LiteralPath $logFile -Encoding UTF8 -PassThru
}
LogMessage "スクリプトを開始したよ(*´ー`*)"
(中略)
LogMessage "スクリプトを終了するよ(*´ー`*)"
=====<Logging-AddContent.ps1>=====
出力結果はリダイレクト演算子を使ったものと同様です。
追記ではなく上書きする場合はSet-Contentを使います。
Add-Contentは特徴としてファイル書き込み時にファイルに読み込み/書き込みロックをかけるため、処理中はファイルを開けなくなる場合があります。
内部的に、読み書きをロックして開く → 書き込み → 閉じる が繰り返されるイメージです。
書き込み中にファイルを開くと以下のようなポップアップが表示されます。
■Tee-Objectの使用
=====<Logging-Tee.ps1>=====
# ログ出力先
$logFile = $PSScriptRoot + "\log\logfile.txt"
# LogMessage関数を作成
function LogMessage($Message){
Write-Output "$(Get-Date -Format G): $Message" `
|Tee-Object -FilePath $logFile -Append
}
LogMessage "スクリプトを開始したよ(*´ー`*)"
(中略)
LogMessage "スクリプトを終了するよ(*´ー`*)"
=====<Logging-Tee.ps1>=====
Linuxのteeコマンドのような標準出力とファイルへ書き込むコマンドです。
エンコードの指定は出来ません。
後述の方法で、ファイルではなく変数へ渡すことも出来ます。
■Out-Fileの使用
=====<Logging-OutFile.ps1>=====
# ログ出力先
$logFile = $PSScriptRoot + "\log\logfile.txt"
# LogMessage関数を作成
function LogMessage($Message){
$msg = "$(Get-Date -Format G): $Message"
Write-Output $msg
$msg |Out-File -LiteralPath $logFile -Encoding UTF8 -Append
}
LogMessage "スクリプトを開始したよ(*´ー`*)"
(中略)
LogMessage "スクリプトを終了するよ(*´ー`*)"
=====<Logging-OutFile.ps1>=====
リダイレクト演算子と似ていますが、こちらはエンコードの指定が出来ます。
Tee-Objectと組み合わせて以下のような記述も可能です。
===================
function LogMessage($Message){
Write-Output "$(Get-Date -Format G): $Message" `
|Tee-Object -Variable msg
$msg |Out-File -LiteralPath $logFile -Encoding UTF8 -Append
}
===================
エンコード指定が可能で読み込み禁止がかからないOut-Fileが基本的には最良の選択肢かなぁと思います。