Powershell: Capture du programme stdout et stderr pour séparer les variables

est-il possible de rediriger stdout d'un programme externe vers une variable et stderr d'un programme externe vers une autre variable en une seule exécution?

par exemple:

 $global:ERRORS = @();
 $global:PROGERR = @();

 function test(){
      # Can we redirect errors to $PROGERR here, leaving stdout for $OUTPUT?
      $OUTPUT = (& myprogram.exe 'argv[0]', 'argv[1]');

      if ( $OUTPUT | select-string -Pattern "foo" ) {
           # do stuff
      } else {
           $global:ERRORS += "test(): oh noes! 'foo' missing!";
      }
 }

 test;
 if ( @($global:ERRORS).length -gt 0 ) {
      Write-Host "Script specific error occurred";
      foreach ( $err in $global:ERRORS ) {
           $host.ui.WriteErrorLine("err: $err");
      }
 } else {
      Write-Host "Script ran fine!";
 }

 if ( @($global:PROGERR).length -gt 0 ) {
      # do stuff
 } else {
      Write-Host "External program ran fine!";
 }

un exemple ennuyeux cependant je me demande si cela est possible?

30
demandé sur mklement0 2014-06-14 20:44:00

4 réponses

la façon la plus facile de faire cela est d'utiliser un fichier pour la sortie stderr par exemple:

$output = & myprogram.exe 'argv[0]', 'argv[1]' 2>stderr.txt
$err = get-content stderr.txt
if ($LastExitCode -ne 0) { ... handle error ... }

j'utiliserais aussi $LastExitCode pour vérifier les erreurs de la console native exes.

8
répondu Keith Hill 2014-06-15 19:44:07

une option est de combiner la sortie de stdout et stderr en un seul flux, puis filtrer.

données de stdout seront des chaînes, tandis que stderr produit Système.Gestion.Automatisation.ErrorRecord objects.

$allOutput = & myprogram.exe 2>&1
$stderr = $allOutput | ?{ $_ -is [System.Management.Automation.ErrorRecord] }
$stdout = $allOutput | ?{ $_ -isnot [System.Management.Automation.ErrorRecord] }
24
répondu Aaron Schultz 2015-10-07 21:49:01

vous devriez utiliser les options Start-Process avec-RedirectStandardError-RedirectStandardOutput. Ce autre post a un excellent exemple comment faire (échantillonné à partir de ce post ci-dessous):

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "ping.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = "localhost"
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
Write-Host "stdout: $stdout"
Write-Host "stderr: $stderr"
Write-Host "exit code: " + $p.ExitCode
7
répondu AckSynFool 2014-06-15 06:49:54

C'est aussi une alternative que j'ai utilisée pour rediriger stdout et stderr d'une ligne de commande tout en montrant la sortie pendant l'exécution powershell:

$command = "myexecutable.exe my command line params"

Invoke-Expression $command -OutVariable output -ErrorVariable errors
Write-Host "STDOUT"
Write-Host $output
Write-Host "STDERR"
Write-Host $errors

juste une autre possibilité pour compléter ce qui a déjà été donné.

gardez à l'esprit que cela ne fonctionne pas toujours en fonction de la façon dont le script est invoqué, j'ai eu des problèmes avec-imparable et-ErrorVariable lorsqu'il est invoqué à partir d'une ligne de commande standard plutôt que d'une Ligne de commande PowerShell comme ceci:

PowerShell -File ".\FileName.ps1"

une alternative qui semble fonctionner dans la plupart des circonstances est celle-ci:

$stdOutAndError = Invoke-Expression "$command 2>&1"

malheureusement, vous perdrez la sortie de la ligne de commande pendant l'exécution du script et devrez Write-Host $stdOutAndError après le retour de la commande pour en faire "une partie de l'enregistrement" (comme une partie d'un jet de fichier Jenkins). Et malheureusement, il ne sépare pas stdout et stderr.

2
répondu James Eby 2016-08-11 02:44:59