web-dev-qa-db-de.com

Umleitung der Standard- und Fehlerausgabe an dieselbe Protokolldatei

Ich muss die Standardausgabe und das Fehlerprotokoll von mehreren Prozessen in einer einzigen Protokolldatei zusammenfassen.

Daher muss jede Ausgabe anhängen an diese Protokolldatei.

Ich möchte alle Jobs mit folgenden Zeilen aufrufen:

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

Wo muss ich die Informationen anhängen?

51
PSBeginner

Um an eine Datei anzuhängen, müssen Sie einen etwas anderen Ansatz verwenden. Sie können den Standardfehler und die Standardausgabe eines einzelnen Prozesses weiterhin in eine Datei umleiten. Um ihn jedoch an eine Datei anzuhängen, müssen Sie eine der folgenden Aktionen ausführen:

  1. Lesen Sie den Inhalt der stdout/stderr-Datei, die mit Start-Process Erstellt wurde.
  2. Verwenden Sie nicht Start-Process und verwenden Sie der Anrufer, &
  3. Verwenden Sie Start-Process nicht und starten Sie den Prozess mit .NET-Objekten

Der erste Weg würde so aussehen:

$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

Der zweite Weg würde so aussehen:

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

Oder dieses:

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

Der dritte Weg:

$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

Andy gab mir ein paar gute Hinweise, aber ich wollte es noch sauberer machen. Ganz zu schweigen davon, dass sich PowerShell bei der Methode 2>&1 >> Bei mir beschwert hat, dass auf die Protokolldatei von einem anderen Prozess zugegriffen wird, d. Also hier ist, wie ich es herumgearbeitet habe.

Lassen Sie uns zuerst einen netten Dateinamen generieren, aber das ist wirklich nur um pedantisch zu sein:

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

Und hier beginnt der Trick:

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

Mit start-transcript Und stop-transcript Können Sie ALLE Ausgaben von PowerShell-Befehlen in eine einzelne Datei umleiten, aber bei externen Befehlen funktioniert dies nicht richtig . Lasst uns also einfach alle Ausgaben auf die Standardausgabe von PS umleiten und Transkription den Rest erledigen lassen.

Tatsächlich habe ich keine Ahnung, warum die MS-Ingenieure sagen, dass sie dies "aufgrund der hohen Kosten und der damit verbundenen technischen Komplexität" noch nicht behoben haben, wenn es auf solch einfache Weise umgangen werden kann.

In jedem Fall ist das Ausführen jedes einzelnen Befehls mit start-process Ein großes Durcheinander, aber mit dieser Methode müssen Sie nur den 2>&1 | Write-Output - Code an jede Zeile anhängen, in der externe Befehle ausgeführt werden.

19
bviktor

Wie Unix-Shells unterstützt PowerShell > leitet mit den meisten von Unix bekannten Variationen weiter, einschließlich 2>&1 (obwohl seltsam, Reihenfolge spielt keine Rolle - 2>&1 > file funktioniert genauso wie das normale > file 2>&1).

Wie die meisten modernen Unix-Shells verfügt auch PowerShell über eine Verknüpfung zum Umleiten von Standardfehlern und Standardausgaben auf dasselbe Gerät. Im Gegensatz zu anderen Umleitungsverknüpfungen, die weitgehend der Unix-Konvention entsprechen, wird für die Verknüpfung zum Erfassen aller Dateien eine neue sigil und wie folgt geschrieben: *>.

Ihre Implementierung könnte also sein:

& myjob.bat *>> $logfile
19
Guss

Vielleicht ist es nicht ganz so elegant, aber das Folgende könnte auch funktionieren. Ich vermute asynchron wäre das keine gute Lösung.

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