我有一个将输出发送到日志文件的进程。我想编写一个 Powershell 脚本来启动此过程,等待它完成,并在其运行时将其日志文件实时跟踪到控制台。
我试过这个:
$procs = Start-Process "some_process.exe"
$logjob = Start-Job -Arg "some_logfile.log" -ScriptBlock {
param($file)
Get-Content $file -wait | foreach { Write-Host($_) }
}
$procs | Wait-Process
$logjob | Stop-Job
...以及其他类似的安排,使用工作。但看起来作业的输出只有在作业停止后才可用,或者通过从中发送“事件”而可用,这听起来好像它们并不是真正用于日志消息之类的快速事物(例如,大约 1 分钟内 100,000 行) ).
还有其他方法可以做到这一点吗?我的下一个选择是从
Start-Process
调用“tail”,这将完成工作(我认为 - 希望这不会有相同的“等待停止”输出行为),但感觉不对。
除非您从作业中检索作业输出,否则不会显示作业输出。为什么不简单地逆转你正在做的事情:将进程作为一项作业启动,并在控制台上跟踪日志文件:
$job = Start-Job -ScriptBlock { & "some_process.exe" }
Get-Content "some_logfile.log" -Wait
如果您希望尾部在进程终止时终止,您可以将这两个作业作为作业运行,并在另一个作业运行时从日志作业中检索输出:
$pjob = Start-Job -ScriptBlock { & "some_process.exe" }
$ljob = Start-Job -ScriptBlock { Get-Content "some_logfile.log" -Wait }
while ($pjob.State -eq 'Running' -and $ljob.HasMoreData) {
Receive-Job $ljob
Start-Sleep -Milliseconds 200
}
Receive-Job $ljob
Stop-Job $ljob
Remove-Job $ljob
Remove-Job $pjob
我遇到了同样的问题并制定了以下解决方案:
Function Start-FileTailUntilProcessExits($FileToTail, $ProcessToWatch, $TimeoutSeconds) {
$fs = $null
$sr = $null
$timeToAbort = (Get-Date).AddSeconds($TimeoutSeconds)
$timedOut = $false
while ($true) {
if (Test-Path $FileToTail) { # Wait for file to exist
if ($null -eq $sr) {
$fs = New-Object IO.FileStream ($FileToTail, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::ReadWrite)
$sr = New-Object IO.StreamReader ($fs)
}
while ($true) {
$line = $sr.ReadLine()
if ($null -eq $line) {
# Read as many lines as are in the file currently
# and then break so we can check on the status of the process and timeout
# If lines are added later, the StreamReader will pick up where it left off and only log new lines.
break
}
Write-Host $line
}
}
if ($ProcessToWatch.HasExited) {
Write-Host "Process has exited, so stop tailing the log"
break
}
if ((Get-Date) -gt $timeToAbort) {
$timedOut = $true
break
}
Start-Sleep -Seconds 1
}
if ($null -ne $sr) {
$sr.Dispose()
}
if ($null -ne $fs) {
$fs.Dispose()
}
if ($timedOut) {
Write-Error "Process timed out"
}
}