
Warum werden Invoke-Command
bei der Remote-Ausführung von Befehlen andere Ergebnisse erzielt als bei der lokalen Ausführung derselben Befehle auf demselben System?
Diese remote aufgerufenen Befehle zeigen vier leere Zeilen an:
PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }
Während diese lokalen Befehle die erwartete Ausgabe ergeben:
PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }
11 Dir(s) 828,179,570,688 bytes free
Wenn ich zuerst einen starte Enter-PSSession cluster02
und dann ausführe, geben beide Befehle die erwartete Ausgabe zurück.
Handelt es sich um einen Fehler in dieser alten PowerShell (Windows 2012) oder übersehe ich eine PS-Eigenart? Wenn es ein Fehler oder eine Eigenart ist, wann tritt sie dann auf? Mit anderen Worten: Kann man aus diesem seltsamen Verhalten etwas lernen?
Antwort1
Ihr Problem besteht darin, dass Sie versuchen, die Remoteausführung cmd /c
mit einem cmd- dir
Befehl durchzuführen und diesen dann remote an einen PowerShell-Befehl weiterzuleiten.
Während Sie davon ausgehen, dass dies bei der Remote-Ausführung genau so funktioniert wie lokal, gibt es bekanntermaßen Unterschiede und kann zu Verwirrung führen.
Wie in derBefehle, die ein Benutzerprofil erfordern, können bei der Remote-Ausführung fehlschlagenPost
Das Problem besteht darin, dass Sie beim Herstellen einer Verbindung zu einem Remotecomputer keine vollständige Benutzerumgebung einrichten. Technisch gesehen melden Sie sich nicht im üblichen Sinne bei der Maschine an. Sie authentifizieren sich zwar, aber auf die gleiche Weise, wie Sie sich bei einem freigegebenen Ordner authentifizieren würden. Ihre Remoteverbindung verfügt nicht über ein vollständiges Benutzerprofil, und daher können bei allem, was eines erwartet, Fehler auftreten und fehlschlagen (auch wenn diese Fehler nicht angezeigt werden).
Leider gibt es hierfür keine einfache Lösung.
Wenn ich es Invoke-Command -ScriptBlock {}
auf einem Remotecomputer ausführe, versuche ich, die Befehle so weit wie möglich auf PowerShell zu beschränken. Sie sollten ausführlich testen, ob Sie cmd und PowerShell mischen, da dies möglicherweise nicht auf die gleiche Weise funktioniert, wie wenn Sie es ausführen, während Sie interaktiv am System angemeldet sind.
Remote PowerShell, freien Speicherplatz auf dem Laufwerk in Bytes abrufen (keine cmd
)
Invoke-Command -ComputerName Cluster02 -ScriptBlock {(Get-PSDrive C).Free}
Ausgabe
599257099776
Problemumgehungen
Das Festlegen der Ausgabe Invoke-Command
als Variable und das anschließende Auswählen der Zeichenfolge und der Zeileneigenschaft daraus scheint für die von Ihnen bevorzugte Ausgabe ausschlaggebend zu sein.
PowerShell (Variante 1)
$var = Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\" };
($var| select-string 'bytes free').Line.Trim();
Ausgabe
11 Dir(s) 36,011,925,504 bytes free
Das Problem ist wahrscheinlichaufgrund des Aufrufs cmd /c
und der anschließenden Auswahl der passenden Zeichenfolge daraus durch PowerShell-Pipe in der remote aufgerufenen Sitzung. Ich umgehe dieses Problem, indem ich die vollständige Ausgabe von speichere, invoke-command
die korrekt als Variable außerhalb von zurückgegeben wird invoke-command
, und diese Variable dann auch außerhalb von entsprechend analysiere invoke-command
.
PowerShell (Variante 2)
Hier gilt das Gleiche wie oben, aber anstatt eine Variable in die Mischung zu werfen, leiten Sie sie einfach Invoke-Command
direkt an die Select-String
Abfrage weiter.
Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free';
Oder sogar so etwas wie das hier ...
(Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free').Line.Trim()
Antwort2
(Bitte bewerten Sie die akzeptierte Antwort auch positiv, wenn Ihnen diese TLDR-Version gefallen hat.)
TLDR-Richtlinien
Beim Remote-Ausführen von Skriptblöcken:
- Vermeiden Sie wenn möglich die Ausführung von allem, was nicht natives PowerShell ist. Ersetzen Sie es beispielsweise
cmd /c dir c:\|sls 'bytes free'
durch(Get-PSDrive C).Free
. - Wenn nicht, führen Sie die geringstmögliche Verarbeitung in der Remote-Shell aus. Verschieben Sie beispielsweise die Auswahlzeichenfolge wie folgt aus der Remote-Shell:
Invoke-Command cluster02 { cmd /c "dir c:\" } | sls 'bytes free'
.