web-dev-qa-db-ja.com

同じログファイルに追加する標準およびエラー出力のリダイレクト

複数のプロセスから標準出力とエラーログを1つのログファイルに収集する必要があります。

したがって、すべての出力は、このログファイルにappendである必要があります。

次のような行ですべてのジョブを呼び出したい:

$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait

追加する情報をどこに置く必要がありますか?

51
PSBeginner

ファイルに追加するには、少し異なるアプローチを使用する必要があります。個々のプロセスの標準エラーと標準出力をファイルにリダイレクトすることもできますが、ファイルに追加するには、次のいずれかを実行する必要があります。

  1. Start-Processによって作成されたstdout/stderrファイルの内容を読む
  2. Start-Processを使用せず、 呼び出し演算子、& を使用します
  3. Start-Processを使用せず、.NETオブジェクトでプロセスを開始します

最初の方法は次のようになります。

$myLog = "C:\File.log"
$stdErrLog = "C:\stderr.log"
$stdOutLog = "C:\stdout.log"
Start-Process -File myjob.bat -RedirectStandardOutput $stdOutLog -RedirectStandardError $stdErrLog -wait
Get-Content $stdErrLog, $stdOutLog | Out-File $myLog -Append

2番目の方法は次のようになります。

& myjob.bat 2>&1 >> C:\MyLog.txt

またはこれ:

& myjob.bat 2>&1 | Out-File C:\MyLog.txt -Append

3番目の方法:

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "myjob.bat"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = ""
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$output = $p.StandardOutput.ReadToEnd()
$output += $p.StandardError.ReadToEnd()
$output | Out-File $myLog -Append
73
Andy Arismendi

アンディは私に良い指針をくれましたが、もっときれいな方法でやりたかったのです。言うまでもなく、2>&1 >>メソッドでは、PowerShellが別のプロセス、つまりstderrとstdoutの両方がアクセスのためにファイルをロックしようとすることでログファイルにアクセスすることについて不平を言いました。だからここに私がそれを回避した方法があります。

最初に、ニースのファイル名を生成しましょう。しかし、それは本当にただの教訓的です:

$name = "sync_common"
$currdate = get-date -f yyyy-MM-dd
$logfile = "c:\scripts\$name\log\$name-$currdate.txt"

そして、ここからトリックが始まります:

start-transcript -append -path $logfile

write-output "starting sync"
robocopy /mir /copyall S:\common \\10.0.0.2\common 2>&1 | Write-Output
some_other.exe /exeparams 2>&1 | Write-Output
...
write-output "ending sync"

stop-transcript

start-transcriptおよびstop-transcriptを使用すると、PowerShellコマンドのすべての出力を単一のファイルにリダイレクトできますが、 外部コマンドでは正しく機能しません 。したがって、それらのすべての出力をPSのstdoutにリダイレクトし、残りはトランスクリプトに任せましょう。

実際、MSのエンジニアが、このような単純な方法で回避できるのに、「高コストと技術的な複雑さのために」これをまだ修正していないと言う理由がわかりません。

いずれにせよ、start-processですべてのコマンドを実行するのは非常に煩雑ですが、この方法では、外部コマンドを実行する各行に2>&1 | Write-Outputコードを追加するだけです。

19
bviktor

Unixシェルのように、PowerShellは>リダイレクトをサポートします。これには、2>&1(奇妙なことに、順序は関係ありません-2>&1 > fileは通常の> file 2>&1)。

ほとんどの最新のUnixシェルと同様に、PowerShellには標準エラーと標準出力の両方を同じデバイスにリダイレクトするためのショートカットがありますが、Unixの慣習にほぼ従う他のリダイレクトショートカットとは異なり、すべてのショートカットのキャプチャでは新しい sigil のように書かれています:*>

したがって、実装は次のようになります。

& myjob.bat *>> $logfile
19
Guss

たぶんそれはそれほどエレガントではないかもしれませんが、以下もうまくいくかもしれません。非同期的にこれは良い解決策ではないと思います。

$p = Start-Process myjob.bat -redirectstandardoutput $logtempfile -redirecterroroutput $logtempfile -wait
add-content $logfile (get-content $logtempfile)
0
John Mignosa