Je voudrais exécuter un processus externe et capturer sa sortie de commande dans une variable dans PowerShell. J'utilise actuellement ceci:
$params = "/verify $pc /domain:hosp.uhhg.org"
start-process "netdom.exe" $params -WindowStyle Hidden -Wait
J'ai confirmé que la commande s'exécute mais je dois capturer la sortie dans une variable. Cela signifie que je ne peux pas utiliser le -RedirectOutput car cela ne redirige que vers un fichier.
powershell
process
Adam Bertram
la source
la source
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.-Credential
paramètreStart-Process
est un must - mais seulement alors (et si vous voulez exécuter une commande dans une fenêtre séparée). Et il faut être conscient des limitations inévitables dans ce cas: aucune capacité à capturer la sortie, sauf en tant que texte - non entrelacé - dans des fichiers , via-RedirectStandardOutput
et-RedirectStandardError
.Réponses:
As-tu essayé:
$OutputVariable = (Shell command) | Out-String
la source
Shell Command
par ce que vous voulez exécuter. C'est si simple.-i
option sans spécifier de fichier de sortie. La2>&1
solution consiste à rediriger la sortie en utilisant comme décrit dans certaines des autres réponses.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 pasStart-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 ):
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 :
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
: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.
: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):
Cependant, pour les commandes externes, les éléments suivants sont plus susceptibles de fonctionner comme prévu:
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 vers
Out-String
:$cmdOutput = <command> | Out-String
La redirection de stderr vers stdout avec
2>&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 , laissezcmd.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
invoquecmd.exe
avec commande<command>
et quitte après<command>
avoir terminé.2>&1
, ce qui garantit que la redirection est transmise aucmd.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'exceptioncmd.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é par2>&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 avec
Out-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..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 avec
Write-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):la source
<command>
, vous ne devez pas combiner l'exécutable et ses arguments dans une seule chaîne; avec l'invocation viacmd /c
vous pouvez le faire, et cela dépend de la situation, que cela ait un sens ou non. De quel scénario parlez-vous et pouvez-vous donner un exemple minimal?+
opérateur; ce qui suit fonctionne également:cmd /c c:\mycommand.exe $Args '2>&1'
- PowerShell prend soin de transmettre les éléments de$Args
sous forme de chaîne séparée par des espaces dans ce cas, une fonctionnalité appelée splatting .'2>&1'
partie, et ne pas enfermer()
comme beaucoup de scripts ont tendance à le faire.Si vous souhaitez également rediriger la sortie d'erreur, vous devez faire:
Ou, si le nom du programme contient des espaces:
la source
Ou essayez ceci. Il capturera la sortie dans la variable $ scriptOutput:
la source
$scriptOutput = & "netdom.exe" $params
Un autre exemple concret:
Notez que cet exemple inclut un chemin (qui commence par une variable d'environnement). Notez que les guillemets doivent entourer le chemin et le fichier EXE, mais pas les paramètres!
Remarque: n'oubliez pas le
&
caractère devant la commande, mais en dehors des guillemets.La sortie d'erreur est également collectée.
Il m'a fallu un certain temps pour que cette combinaison fonctionne, alors j'ai pensé que je la partagerais.
la source
J'ai essayé les réponses, mais dans mon cas, je n'ai pas obtenu la sortie brute. Au lieu de cela, il a été converti en une exception PowerShell.
Le résultat brut que j'ai obtenu avec:
la source
J'ai fait fonctionner les éléments suivants:
$ result vous donne le nécessaire
la source
Cette chose a fonctionné pour moi:
la source
Si tout ce que vous essayez de faire est de capturer la sortie d'une commande, cela fonctionnera bien.
Je l'utilise pour changer l'heure du système, car je
[timezoneinfo]::local
produit toujours les mêmes informations, même après que vous ayez apporté des modifications au système. C'est la seule façon dont je peux valider et enregistrer le changement de fuseau horaire:Cela signifie que je dois ouvrir une nouvelle session PowerShell pour recharger les variables système.
la source