Redirection de la sortie standard et de l’erreur s’ajoutant au même fichier journal

Je dois collecter la sortie standard et le journal des erreurs de plusieurs processus dans un seul fichier journal.

Ainsi, chaque sortie doit être ajoutée à ce fichier journal.

Je veux appeler tous les travaux avec des lignes comme ceci:

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

Où dois-je mettre les informations à append?

Pour append à un fichier, vous devez utiliser une approche légèrement différente. Vous pouvez toujours redirect une erreur standard de processus individuel et une sortie standard vers un fichier, mais pour l’append à un fichier, vous devez effectuer l’une des opérations suivantes:

  1. Lire le contenu du fichier stdout / stderr créé par Start-Process
  2. Ne pas utiliser Start-Process et utiliser l’opérateur d’appel
  3. Ne pas utiliser Start-Process et démarrer le processus avec des objects .NET

La première façon ressemblerait à ceci:

 $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 

La seconde façon ressemblerait à ceci:

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

Ou ca:

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

La troisième voie:

 $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 

Andy m’a donné de bons conseils, mais je voulais le faire d’une manière encore plus propre. Sans compter qu’avec la méthode 2>&1 >> , PowerShell s’est plaint du fait que le fichier journal était accédé par un autre processus, à la fois stderr et stdout essayant de verrouiller le fichier pour y accéder, je suppose. Alors, voici comment j’ai travaillé.

D’abord, générons un beau nom de fichier, mais c’est juste pour être pédant:

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

Et voici où le tour commence:

 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 

Avec start-transcript et stop-transcript vous pouvez redirect TOUTES les commandes PowerShell vers un seul fichier, mais cela ne fonctionne pas correctement avec les commandes externes . Donc, redirigeons toutes les sorties de celles-ci vers la sortie standard de PS et laissons la transcription faire le rest.

En fait, je n’ai aucune idée de la raison pour laquelle les ingénieurs MS disent qu’ils n’ont pas encore résolu ce problème “en raison du coût élevé et des complexités techniques impliquées”, qui peuvent être résolus de manière aussi simple.

Quoi qu’il en soit, exécuter chaque commande avec start-process est très encombrant, mais avec cette méthode, tout ce que vous avez à faire est d’append les 2>&1 | Write-Output 2>&1 | Write-Output code pour chaque ligne exécutant des commandes externes.

Comme les shells Unix, Powershell supporte > redirections avec la plupart des variations connues sous Unix, y compris 2>&1 (bien que bizarrement, l’ordre n’a pas d’importance – 2>&1 > file fonctionne comme le > file 2>&1 normal > file 2>&1 ).

Comme la plupart des shells Unix modernes, Powershell a également un raccourci pour redirect à la fois stderr et stdout vers le même périphérique, mais contrairement aux autres raccourcis de redirection qui suivent à peu près la convention Unix, le raccourci capture all utilise un nouveau sigil: *> .

Donc, votre implémentation pourrait être:

 & myjob.bat *>> $logfile 

Peut-être pas aussi élégant. Mais cela fonctionnerait-il aussi? Je soupçonne de manière asynchrone que ce ne serait pas une bonne solution.

 $p=start-process myjob.bat -redirectstandardoutput $logtempfile -redirecterroroutput $logtempfile -wait add-content $logfile (get-content $logtempfile)