Ich möchte einen externen Prozess ausführen und dessen Befehlsausgabe in einer Variablen in PowerShell erfassen. Ich benutze derzeit Folgendes:
$params = "/verify $pc /domain:hosp.uhhg.org"
start-process "netdom.exe" $params -WindowStyle Hidden -Wait
Ich habe bestätigt, dass der Befehl ausgeführt wird, aber ich muss die Ausgabe in einer Variablen erfassen. Dies bedeutet, dass ich den -RedirectOutput nicht verwenden kann, da dieser nur zu einer Datei umleitet.
powershell
process
Adam Bertram
quelle
quelle
Start-Process
diese Option nicht , um (per Definition externe) Konsolenanwendungen synchron auszuführen. Rufen Sie sie einfach direkt auf , wie in jeder Shell. zu wissen :netdom /verify $pc /domain:hosp.uhhg.org
. Auf diese Weise bleibt die Anwendung mit den Standard-Streams der aufrufenden Konsole verbunden, sodass die Ausgabe durch einfache Zuweisung erfasst werden kann$output = netdom ...
. Die meisten der unten angegebenen Antworten verzichten implizitStart-Process
zugunsten einer direkten Ausführung.-Credential
Parameter verwenden möchteStart-Process
ein Muss - aber nur dann (und wenn Sie einen Befehl in einem separaten Fenster ausführen möchten). Und man sollte sich der unvermeidbaren Einschränkungen in diesem Fall bewusst sein: Keine Möglichkeit, die Ausgabe zu erfassen, außer als - nicht verschachtelter - Text in Dateien über-RedirectStandardOutput
und-RedirectStandardError
.Antworten:
Hast du es versucht:
$OutputVariable = (Shell command) | Out-String
quelle
Shell Command
durch alles, was Sie ausführen möchten. So einfach ist das.-i
Option verwenden, ohne eine Ausgabedatei anzugeben.2>&1
Die Lösung besteht darin, die Ausgabe wie in einigen anderen Antworten beschrieben umzuleiten.Hinweis: Der Befehl in der Frage verwendet
Start-Process
, wodurch die direkte Erfassung der Ausgabe des Zielprogramms verhindert wird. Im Allgemeinen verwenden Sie keineStart-Process
Konsolenanwendungen synchron auszuführen - nur invoke sie direkt , wie in jeder Schale. Auf diese Weise bleibt die Anwendung mit den Standard-Streams der aufrufenden Konsole verbunden, sodass die Ausgabe durch einfache Zuweisung erfasst werden$output = netdom ...
kann (siehe unten).Grundsätzlich funktioniert das Erfassen der Ausgabe von externen Dienstprogrammen genauso wie bei PowerShell-nativen Befehlen (möglicherweise möchten Sie eine Auffrischung zum Ausführen externer Tools ):
Man beachte , dass
$cmdOutput
ein empfängt Array von Objekten , wenn<command>
produziert mehr als 1 Ausgangsobjekt , das in dem Fall eines externen Programms bedeutet einen String - Array enthält die Ausgabe der Programmzeilen .Wenn Sie
$cmdOutput
immer eine einzelne - möglicherweise mehrzeilige - Zeichenfolge erhalten möchten , verwenden Sie$cmdOutput = <command> | Out-String
So erfassen Sie die Ausgabe in einer Variablen und drucken auf dem Bildschirm :
Wenn
<command>
es sich um ein Cmdlet oder eine erweiterte Funktion handelt, können Sie den allgemeinen Parameter-OutVariable
/ verwenden-ov
:Beachten Sie, dass mit
-OutVariable
, im Gegensatz zu den anderen Szenarien$cmdOutput
ist immer eine Sammlung , auch wenn nur ein Objekt ausgegeben wird. Insbesondere wird eine Instanz vom Array-ähnlichen[System.Collections.ArrayList]
Typ zurückgegeben.In dieser GitHub-Ausgabe finden Sie eine Diskussion dieser Diskrepanz.
Verwenden Sie zum Erfassen der Ausgabe mehrerer Befehle entweder einen Unterausdruck (
$(...)
) oder rufen Sie einen Skriptblock ({ ... }
) mit&
oder auf.
:Beachten Sie, dass die allgemeine Notwendigkeit,
&
einem einzelnen Befehl (dessen Aufruf / Pfad) in Anführungszeichen steht (z. B.),$cmdOutput = & 'netdom.exe' ...
nicht mit externen Programmen an sich zusammenhängt (dies gilt auch für PowerShell-Skripte), sondern eine Syntaxanforderung ist : PowerShell Analysiert eine Anweisung, die standardmäßig mit einer Zeichenfolge in Anführungszeichen im Ausdrucksmodus beginnt , während der Argumentmodus zum Aufrufen von Befehlen (Cmdlets, externe Programme, Funktionen, Aliase) erforderlich ist&
.Der Hauptunterschied zwischen
$(...)
und& { ... }
/ und. { ... }
besteht darin, dass erstere alle Eingaben im Speicher sammeln, bevor sie als Ganzes zurückgegeben werden, während letztere die Ausgabe streamen , die für die Eins-zu-Eins-Pipeline-Verarbeitung geeignet ist.Weiterleitungen funktionieren grundsätzlich genauso (siehe jedoch die folgenden Einschränkungen):
Bei externen Befehlen funktioniert jedoch mit größerer Wahrscheinlichkeit Folgendes wie erwartet:
Überlegungen zu externen Programmen:
Externe Programme geben , da sie außerhalb des PowerShell-Typsystems ausgeführt werden, immer nur Zeichenfolgen über ihren Erfolgsstrom (stdout) zurück.
Wenn die Ausgabe mehr als eine Zeile enthält , teilt PowerShell sie standardmäßig in ein Array von Zeichenfolgen auf . Genauer gesagt werden die Ausgabezeilen in einem Array vom Typ gespeichert,
[System.Object[]]
dessen Elemente Zeichenfolgen ([System.String]
) sind.Wenn die Ausgabe eine einzelne , möglicherweise mehrzeilige Zeichenfolge sein soll , leiten Sie Folgendes an
Out-String
:$cmdOutput = <command> | Out-String
Das Umleiten von stderr zu stdout mit
2>&1
, um es auch als Teil des Erfolgsstroms zu erfassen, ist mit folgenden Einschränkungen verbunden :Um
2>&1
stdout und stderr an der Quelle zusammenzuführen , lassen Siecmd.exe
die Umleitung mit den folgenden Redewendungen ablaufen:$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /c
wirdcmd.exe
mit Befehl aufgerufen<command>
und nach<command>
Beendigung beendet.2>&1
sicherzustellen, dass die Umleitung ancmd.exe
PowerShell übergeben und nicht von PowerShell interpretiert wird.Beachten Sie, dass das Einbeziehen
cmd.exe
bedeutet, dass die Regeln für das Escapezeichen von Zeichen und das Erweitern von Umgebungsvariablen standardmäßig zusätzlich zu den eigenen Anforderungen von PowerShell ins Spiel kommen. In PS v3 + können Sie spezielle Parameter--%
(das sogenannte Stop-Parsing-Symbol ) verwenden, um die Interpretation der verbleibenden Parameter durch PowerShell zucmd.exe
deaktivieren , mit Ausnahme von Verweisen auf Umgebungsvariablen im Stil wie%PATH%
.Da Sie mit diesem Ansatz stdout und stderr an der Quelle zusammenführen , können Sie in PowerShell nicht zwischen Zeilen mit stdout- und stderr-Ursprung unterscheiden . Wenn Sie diese Unterscheidung benötigen, verwenden Sie die PowerShell-eigene
2>&1
Umleitung - siehe unten.Verwenden Sie die
2>&1
Umleitung von PowerShell, um festzustellen, welche Zeilen von welchem Stream stammen :Die Stderr- Ausgabe wird als Fehlerdatensätze ( ) und nicht als Zeichenfolgen erfasst
[System.Management.Automation.ErrorRecord]
, sodass das Ausgabearray eine Mischung aus Zeichenfolgen (jede Zeichenfolge repräsentiert eine Standardzeile) und Fehlerdatensätzen (jeder Datensatz repräsentiert eine Standardzeile) enthalten kann . Beachten Sie, dass auf Anforderung2>&1
sowohl die Zeichenfolgen als auch die Fehlerdatensätze über den Erfolgsausgabestream von PowerShell empfangen werden .In der Konsole werden die Fehlerdatensätze rot gedruckt , und der erste erzeugt standardmäßig eine mehrzeilige Anzeige in demselben Format, in dem der nicht terminierende Fehler eines Cmdlets angezeigt wird. nachfolgende Fehlersätze in rot gedruckt werden als gut, aber nur ihre Fehler drucken Nachricht , auf einer einzigen Zeile .
Bei der Ausgabe an die Konsole , die Saiten der Regel kommen zuerst in der Ausgangsanordnung, die durch die Fehlersätze gefolgt (zumindest bei einer Charge von stdout / stderr Linien Ausgang „zur gleichen Zeit“), aber, zum Glück, wenn Sie erfassen die Ausgabe Es ist richtig verschachtelt und verwendet dieselbe Ausgabereihenfolge, die Sie ohne erhalten würden
2>&1
. Mit anderen Worten: Bei der Ausgabe an die Konsole spiegelt die erfasste Ausgabe NICHT die Reihenfolge wider, in der stdout- und stderr-Zeilen vom externen Befehl generiert wurden.Wenn Sie die gesamte Ausgabe in einer einzelnen Zeichenfolge mit erfassen
Out-String
, fügt PowerShell zusätzliche Zeilen hinzu , da die Zeichenfolgendarstellung eines Fehlerdatensatzes zusätzliche Informationen wie location (At line:...
) und category (+ CategoryInfo ...
) enthält. Seltsamerweise gilt dies nur für den ersten Fehlerdatensatz..ToString()
Methode auf jedes Ausgabeobjekt an, um dieses Problem zu umgehen, anstatt auf Folgendes zu verweisenOut-String
:$cmdOutput = <command> 2>&1 | % { $_.ToString() }
;In PS v3 + können Sie Folgendes vereinfachen:
$cmdOutput = <command> 2>&1 | % ToString
(Wenn die Ausgabe nicht erfasst wird, wird als Bonus auch beim Drucken auf der Konsole eine ordnungsgemäß verschachtelte Ausgabe erstellt.)
Alternativ können Sie die Fehleraufzeichnungen herausfiltern und an den Fehlerstrom von PowerShell senden mit
Write-Error
(als Bonus führt dies dazu, dass die Ausgabe auch beim Drucken auf der Konsole ordnungsgemäß verschachtelt wird, wenn die Ausgabe nicht erfasst wird):quelle
<command>
, Sie nicht müssen die ausführbare Datei und ihre Argumente in einer einzigen Zeichenfolge kombinieren; mit Aufruf übercmd /c
Sie können tun so, und es hängt von der Situation , ob es Sinn macht oder nicht. Auf welches Szenario beziehen Sie sich und können Sie ein minimales Beispiel geben?+
Operator nicht benötigen . Folgendes funktioniert ebenfalls:cmd /c c:\mycommand.exe $Args '2>&1'
- PowerShell sorgt dafür, dass die Elemente$Args
in diesem Fall als durch Leerzeichen getrennte Zeichenfolge übergeben werden . Diese Funktion wird als Splatting bezeichnet .'2>&1'
Teil, und nicht()
so viele Skripte enthalten, wie es normalerweise der Fall ist .Wenn Sie auch die Fehlerausgabe umleiten möchten, müssen Sie Folgendes tun:
Oder wenn der Programmname Leerzeichen enthält:
quelle
Oder versuchen Sie es. Die Ausgabe wird in der Variablen $ scriptOutput erfasst:
quelle
$scriptOutput = & "netdom.exe" $params
Ein weiteres Beispiel aus dem wirklichen Leben:
Beachten Sie, dass dieses Beispiel einen Pfad enthält (der mit einer Umgebungsvariablen beginnt). Beachten Sie, dass die Anführungszeichen den Pfad und die EXE-Datei umgeben müssen, nicht jedoch die Parameter!
Hinweis: Vergessen Sie nicht das
&
Zeichen vor dem Befehl, sondern außerhalb der Anführungszeichen.Die Fehlerausgabe wird ebenfalls erfasst.
Es hat eine Weile gedauert, bis diese Kombination funktioniert hat, also dachte ich, ich würde sie teilen.
quelle
Ich habe die Antworten ausprobiert, aber in meinem Fall habe ich die Rohausgabe nicht erhalten. Stattdessen wurde es in eine PowerShell-Ausnahme konvertiert.
Das rohe Ergebnis, mit dem ich kam:
quelle
Ich habe folgendes zum Arbeiten:
$ Ergebnis gibt Ihnen das Notwendige
quelle
Dieses Ding hat bei mir funktioniert:
quelle
Wenn Sie nur versuchen, die Ausgabe eines Befehls zu erfassen, funktioniert dies gut.
Ich verwende es zum Ändern der Systemzeit, da
[timezoneinfo]::local
immer die gleichen Informationen erzeugt werden, auch nachdem Sie Änderungen am System vorgenommen haben. Nur so kann ich die Änderung der Zeitzone validieren und protokollieren:Das bedeutet, dass ich eine neue PowerShell- Sitzung öffnen muss , um die Systemvariablen neu zu laden.
quelle