Remarque: La commande de la question utilise Start-Process
, ce qui empêche la capture directe de la sortie du programme cible. En général, ne l'utilisez pas Start-Process
pour exécuter des applications de console de manière synchrone - appelez-les simplement directement , comme dans n'importe quel shell. Cela permet de maintenir l'application connectée aux flux standard de la console appelante, ce qui permet de capturer sa sortie par simple affectation $output = netdom ...
, comme détaillé ci-dessous.
Fondamentalement , la capture de la sortie d' utilitaires externes fonctionne de la même manière qu'avec les commandes natives PowerShell (vous voudrez peut-être un rappel sur la façon d'exécuter des outils externes ):
$cmdOutput = <command> # captures the command's success stream / stdout
Notez que $cmdOutput
reçoit un tableau d'objets si <command>
produit plus d'un objet de sortie , ce qui dans le cas d'un programme externe signifie un tableau de chaînes contenant les lignes de sortie du programme .
Si vous voulez $cmdOutput
toujours recevoir une seule chaîne - potentiellement multiligne - , utilisez
$cmdOutput = <command> | Out-String
Pour capturer la sortie dans une variable et l' imprimer à l'écran :
<command> | Tee-Object -Variable cmdOutput # Note how the var name is NOT $-prefixed
Ou, s'il <command>
s'agit d'une applet de commande ou d' une fonction avancée , vous pouvez utiliser le paramètre commun
-OutVariable
/-ov
:
<command> -OutVariable cmdOutput # cmdlets and advanced functions only
Notez que -OutVariable
, contrairement aux autres scénarios, $cmdOutput
est toujours une collection , même si un seul objet est généré. Plus précisément, une instance du [System.Collections.ArrayList]
type de type tableau est renvoyée.
Consultez ce problème GitHub pour une discussion de cette différence.
Pour capturer la sortie de plusieurs commandes , utilisez une sous-expression ( $(...)
) ou appelez un bloc de script ( { ... }
) avec &
ou .
:
$cmdOutput = $(<command>; ...) # subexpression
$cmdOutput = & {<command>; ...} # script block with & - creates child scope for vars.
$cmdOutput = . {<command>; ...} # script block with . - no child scope
Notez que le besoin général de préfixer avec &
(l'opérateur d'appel) une commande individuelle dont le nom / chemin est cité - par exemple, $cmdOutput = & 'netdom.exe' ...
- n'est pas lié aux programmes externes en soi (cela s'applique également aux scripts PowerShell), mais est une exigence de syntaxe : PowerShell analyse une instruction qui commence par une chaîne entre guillemets en mode expression par défaut, alors que le mode argument est nécessaire pour appeler des commandes (applets de commande, programmes externes, fonctions, alias), ce qui &
garantit.
La principale différence entre $(...)
et & { ... }
/ . { ... }
est que le premier collecte toutes les entrées en mémoire avant de les renvoyer dans leur ensemble, tandis que les seconds diffusent la sortie, adaptée au traitement en pipeline un par un.
Les redirections fonctionnent également de la même manière, fondamentalement (mais voir les mises en garde ci-dessous):
$cmdOutput = <command> 2>&1 # redirect error stream (2) to success stream (1)
Cependant, pour les commandes externes, les éléments suivants sont plus susceptibles de fonctionner comme prévu:
$cmdOutput = cmd /c <command> '2>&1' # Let cmd.exe handle redirection - see below.
Considérations spécifiques aux programmes externes :
Les programmes externes , car ils fonctionnent en dehors du système de types de PowerShell, ne renvoient que des chaînes via leur flux de réussite (stdout).
Si la sortie contient plus d'une ligne , PowerShell la divise par défaut en un tableau de chaînes . Plus précisément, les lignes de sortie sont stockées dans un tableau de type [System.Object[]]
dont les éléments sont des chaînes ( [System.String]
).
Si vous souhaitez que la sortie soit une chaîne unique , potentiellement multi-lignes , dirigez versOut-String
:
$cmdOutput = <command> | Out-String
La redirection de stderr vers stdout avec2>&1
, afin de le capturer également dans le cadre du flux de réussite, comporte des mises en garde :
Pour faire 2>&1
fusionner stdout et stderr à la source , laissez cmd.exe
gérer la redirection , en utilisant les idiomes suivants:
$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /c
invoque cmd.exe
avec commande <command>
et quitte après <command>
avoir terminé.
- Notez les guillemets simples autour
2>&1
, ce qui garantit que la redirection est transmise au cmd.exe
lieu d'être interprétée par PowerShell.
Notez qu'impliquer cmd.exe
signifie que ses règles pour échapper les caractères et développer les variables d'environnement entrent en jeu, par défaut en plus des propres exigences de PowerShell; dans PS v3 +, vous pouvez utiliser un paramètre spécial --%
(le soi-disant symbole d'arrêt de l'analyse ) pour désactiver l'interprétation des paramètres restants par PowerShell, à l'exception cmd.exe
des références de variable d'environnement -style telles que %PATH%
.
Notez que puisque vous fusionnez stdout et stderr à la source avec cette approche, vous ne pourrez pas faire la distinction entre les lignes d'origine stdout et stderr dans PowerShell; si vous avez besoin de cette distinction, utilisez la propre 2>&1
redirection de PowerShell - voir ci-dessous.
Utilisez la 2>&1
redirection de PowerShell pour savoir quelles lignes proviennent de quel flux :
La sortie Stderr est capturée sous forme d'enregistrements d'erreur ( [System.Management.Automation.ErrorRecord]
) et non de chaînes, de sorte que le tableau de sortie peut contenir un mélange de chaînes (chaque chaîne représentant une ligne stdout) et d'enregistrements d'erreur (chaque enregistrement représentant une ligne stderr) . Notez que, comme demandé par 2>&1
, les chaînes et les enregistrements d'erreur sont reçus via le flux de sortie de réussite de PowerShell ).
Dans la console, les enregistrements d'erreur s'impriment en rouge , et le premier par défaut produit un affichage multiligne , dans le même format que l'erreur sans fin d'une applet de commande afficherait; les enregistrements d'erreurs ultérieurs s'impriment également en rouge, mais n'impriment leur message d' erreur que sur une seule ligne .
Lors de la sortie vers la console , les chaînes viennent généralement en premier dans le tableau de sortie, suivies des enregistrements d'erreurs (au moins parmi un lot de lignes stdout / stderr sortant «en même temps»), mais, heureusement, lorsque vous capturez la sortie , il est correctement entrelacé , en utilisant le même ordre de sortie que vous obtiendriez sans 2>&1
; en d'autres termes: lors de la sortie vers la console , la sortie capturée ne reflète PAS l'ordre dans lequel les lignes stdout et stderr ont été générées par la commande externe.
Si vous capturez la sortie entière dans une seule chaîne avecOut-String
, PowerShell ajoutera des lignes supplémentaires , car la représentation sous forme de chaîne d'un enregistrement d'erreur contient des informations supplémentaires telles que location ( At line:...
) et category ( + CategoryInfo ...
); curieusement, cela ne s'applique qu'au premier enregistrement d'erreur.
- Pour contourner ce problème, appliquez la
.ToString()
méthode pour chaque objet de sortie au lieu de la tuyauterie à Out-String
:
$cmdOutput = <command> 2>&1 | % { $_.ToString() }
;
dans PS v3 +, vous pouvez simplifier comme suit:
$cmdOutput = <command> 2>&1 | % ToString
(En prime, si la sortie n'est pas capturée, cela produit une sortie correctement entrelacée même lors de l'impression sur la console.)
Vous pouvez également filtrer les enregistrements d'erreur sur et les envoyer au flux d'erreur de PowerShell avecWrite-Error
(comme un bonus, si la sortie n'est pas capturé, cela produit la sortie correctement entrelacée même lors de l' impression à la console):
$cmdOutput = <command> 2>&1 | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Error $_
} else {
$_
}
}
Start-Process
pour exécuter des applications de console (par définition externes) de manière synchrone - il suffit de les appeler directement , comme dans n'importe quel shell; à savoir:netdom /verify $pc /domain:hosp.uhhg.org
. Cela permet de maintenir l'application connectée aux flux standard de la console appelante, ce qui permet de capturer sa sortie par simple affectation$output = netdom ...
. La plupart des réponses données ci-dessous renoncent implicitementStart-Process
en faveur de l'exécution directe.