标准和错误输出的重定向附加到同一日志文件

PSB*_*ner 51 powershell powershell-2.0

我需要将标准输出和错误日志从几个进程收集到一个日志文件中.

因此,每个输出都必须附加到此日志文件.

我想用这样的行调用所有作业:

$p=start-process myjob.bat -redirectstandardoutput $logfile -redirecterroroutput $logfile -wait
Run Code Online (Sandbox Code Playgroud)

我需要在哪里附加信息?

And*_*ndi 74

要附加到文件,您需要使用稍微不同的方法.您仍然可以将单个进程标准错误和标准输出重定向到文件,但为了将其附加到文件,您需要执行以下操作之一:

  1. 读取由创建的stdout/stderr文件内容 Start-Process
  2. 不使用Start-Process并使用call运算符 &
  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
Run Code Online (Sandbox Code Playgroud)

第二种方式如下:

& myjob.bat 2>&1 >> C:\MyLog.txt
Run Code Online (Sandbox Code Playgroud)

或这个:

& myjob.bat 2>&1 | Out-File C:\MyLog.txt -Append
Run Code Online (Sandbox Code Playgroud)

第三种方式:

$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
Run Code Online (Sandbox Code Playgroud)

  • 第三种方式在某些情况下导致死锁,请阅读MSDN或在此讨论http://stackoverflow.com/a/8762068/151641 (4认同)

Gus*_*uss 21

与Unix shell一样,PowerShell支持>重定向,其中包含Unix中已知的大多数变体,包括2>&1(但奇怪的是,顺序无关紧要 - 2>&1 > file与正常情况一样> file 2>&1).

像大多数现代Unix shell一样,PowerShell也有一个快捷方式,可以将标准错误和标准输出重定向到同一个设备,不像其他重定向快捷方式几乎遵循Unix惯例,捕获所有快捷方式都使用新的sigil并且写得像这样:*>.

所以你的实现可能是:

& myjob.bat *>> $logfile
Run Code Online (Sandbox Code Playgroud)


bvi*_*tor 20

安迪给了我一些好的指示,但我想以更清洁的方式做到这一点.更不用说2>&1 >>PowerShell向我抱怨另一个进程正在访问的日志文件,即stderr和stdout试图锁定文件以进行访问,我猜.所以这就是我如何处理它的方式.

首先让我们生成一个很好的文件名,但这真的只是为了迂腐:

$name = "sync_common"
$currdate = get-date -f yyyy-MM-dd
$logfile = "c:\scripts\$name\log\$name-$currdate.txt"
Run Code Online (Sandbox Code Playgroud)

这就是技巧开始的地方:

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
Run Code Online (Sandbox Code Playgroud)

使用start-transcriptstop-transcript可以将所有PowerShell命令输出重定向到单个文件,但它无法与外部命令一起正常工作.所以,让我们将这些输出的所有输出重定向到PS的标准输出,然后让记录完成剩下的工作.

事实上,我不知道为什么MS工程师说它们还没有解决这个问题,"由于所涉及的高成本和技术复杂性",它可以以这种简单的方式解决.

无论哪种方式,运行每一个命令start-process是一个巨大的混乱恕我直言,但使用这种方法,你要做的就是将2>&1 | Write-Output代码附加到运行外部命令的每一行.