web-dev-qa-db-fra.com

Redirection des sorties standard et d'erreur en ajoutant le même fichier journal

J'ai besoin de collecter la sortie standard et le journal des erreurs de plusieurs processus dans un seul fichier journal.

Donc, chaque sortie doit ajouter à ce fichier journal.

Je veux appeler tous les emplois avec des lignes comme celle-ci:

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

Où dois-je mettre l'information à annexer?

51
PSBeginner

Afin d’ajouter à un fichier, vous devrez utiliser une approche légèrement différente. Vous pouvez toujours rediriger l'erreur standard et la sortie standard d'un processus individuel vers un fichier. Toutefois, pour l'ajouter à 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 objets .NET

Le premier moyen 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 deuxième 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
73
Andy Arismendi

Andy m'a donné de bons conseils, mais je voulais le faire d'une manière encore plus propre. Sans parler de cela avec le 2>&1 >> Méthode PowerShell m’a déploré que le fichier journal soit utilisé par un autre processus, c’est-à-dire que stderr et stdout essaient de verrouiller le fichier pour y accéder, je suppose. Alors, voici comment je me suis débrouillé.

Générons d’abord un nom de fichier Nice, 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 truc 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 rediriger TOUTES les sorties des commandes PowerShell dans un seul fichier, mais cela ne fonctionne pas correctement avec des commandes externes . Nous allons donc simplement rediriger toute la sortie de ceux-ci vers la sortie standard de PS et laisser transcript faire le reste.

En fait, je ne comprends pas pourquoi les ingénieurs de Microsoft ont dit ne pas encore avoir résolu ce problème "en raison des coûts élevés et des complexités techniques impliquées", alors que cela peut être résolu de manière aussi simple.

De toute façon, en exécutant chaque commande avec start-process est un énorme fouillis IMHO, mais avec cette méthode, tout ce que vous avez à faire est d’ajouter le 2>&1 | Write-Output code à chaque ligne qui exécute des commandes externes.

19
bviktor

Comme les shells Unix, PowerShell prend en charge les redirections > Avec la plupart des variantes connues sous Unix, y compris 2>&1 (Bien qu'étrangement, l'ordre n'a pas d'importance - 2>&1 > file Fonctionne exactement comme d'habitude. > file 2>&1).

Comme la plupart des shells Unix modernes, PowerShell dispose également d’un raccourci permettant de rediriger à la fois les erreurs standard et les sorties standard vers le même périphérique. Toutefois, contrairement à d’autres raccourcis de redirection qui suivent à peu près la convention Unix, le raccourci capturé utilise un nouveau sigil et s'écrit comme suit: *>.

Donc, votre implémentation pourrait être:

& myjob.bat *>> $logfile
19
Guss

Peut-être que ce n’est pas aussi élégant, mais ce qui suit pourrait aussi marcher. 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)
0
John Mignosa