Remote-Funktionalität der Powershell 2
18. Januar 2011Mit der Powershell 2.0 und der Remoting-Funktionalität steht eine neue Art des Fernzugriffs zur Verfügung. Vor allem im Bereich der Fehlersuche und der Systemverwaltung ergeben sich damit effiziente Möglichkeiten, um sehr mächtige Konstrukte mit dem Powershell Scripting anzugehen.
Bill Stewart zeigt in seinem Beitrag, wie das Powershell Remoting einzustellen ist und wie der Administrator das Arbeiten mit einem sogenannten Scriptblock – also einen ganzen Block von Powershell-Befehlen – auf einem oder gar mehreren entfernten Systemen angehen kann. Zudem zeigt der Autor noch, wie das Erzeugen von Powershell-Sitzungen funktioniert, damit ein Systembetreuer auch wiederverwendbare Sessions mit der Powershell anlegen kann. Das führt zu einem sehr effizienten Arbeiten, wenn die Powershell-Aktionen mehrmals auf entfernten Systemen nötig sind.
Bereits die Windows Powershell 1.0 brachte einen gewaltigen Schritt nach vorn, was die Verwaltung und die Automatisierung im Bereich der Windows-Betriebssystemplattformen angeht. Die Grundlage für die Powershell bildet das Dotnet-Framework. Dazu kommt eine konsistente Kommandostruktur (die Cmdlets). Dabei sind bereits viele mächtige Funktionen eingebaut – wie etwa das Formatieren der Ausgabe. Aber auch systeminterne Technologien, wie etwa die Windows Management Instrumentation (WMI), lassen sich mit Hilfe der Powershell besser nutzen.
Allerdings sind viele Cmdlets der ersten Version der Powershell nicht in der Lage, mit entfernten Systemen zusammenzuarbeiten. Nur vereinzelt ist das bei der Powershell 1.0 machbar. Dazu gibt es Cmdlets, die über einen Parameter –ComputerName verfügen. Diese Programme verwenden entweder RPCs (Remote Procedure Calls) oder DCOM-Technologie (Distributed Component Object Model), um die Verbindung zu einem entfernten System aufzubauen.
In vielen Aufgabenbereichen, die mit der Verwaltung von Systeme zu tun haben, lassen sich RPC und DCOM gut verwenden. Doch wenn es um die Diagnose oder gar Fehlersuche geht, wird die Sache schon viel aufwändiger. Dazu ein Beispiel: Das Cmdlet Get-Service ist in der Lage, Informationen über die Dienste eines entfernten Systems zu liefern. Dazu muss man lediglich mit dem Parameter -ComputerName das betreffende System angeben. Doch diese Cmdlet verfügt über keinen Parameter wie etwa -Credential. Daher muss man mit einem Konto angemeldet sein, das auch über die nötigen Berechtigungen auf dem entfernten System verfügt.-Das kann sich dann aber wieder als ein Sicherheitsproblem erweisen.
Ab der Powershell 2.0 gibt es allerdings eine Alternative für das Verbinden mit entfernten Systemen – das sogenannte Powershell Remoting. Diese Funktionalität basiert auf dem Dienst „Windows Remote Management“ (WinRM). Damit wird eine Verbindung mit einem entfernten System aufgebaut und die Kommandos eingegeben, die dann auf dem entfernten System zur Ausführung kommen. Die Ergebnisse werden aber auf dem lokalen System dargestellt.
Powershell 2.0 beziehen
Ab Windows 7 und dem Windows Server 2008 Release 2 (R2) sind Powershell 2.0 und der WinRM-Dienst automatisch enthalten – sprich der Administrator braucht keinen zusätzlichen Installationsvorgang anstoßen. Für die älteren Betriebssysteme wie Windows Vista oder Windows XP (Servicepack 3) beziehungsweise Windows Server 2008 SP2 und Windows Server 2003 SP2 muss man sich dagegen das Paket Windows Management Framework Core besorgen.
Zum Download stehen verschiedene Versionen dieses Pakets zur Verfügung – je nachdem welches Betriebssystem man im Einsatz hat und ob es sich um eine 32- oder eine 64-Bit-Plattform handelt.
Das Aktivieren des Powershell Remotings
Ehe man auf seinen Systemen das Powershell Remoting einsetzen kann, gilt es einige Vorbedingungen zu erfüllen:
- Der Service WinRM muss gestartet sein.
- Es muss ein WinRM Listener laufen, der Verbindungen von mehr als einer IP-Adresse akzeptiert.
- Die Windows-Firewall muss so eingestellt sein, dass sie WinRM-Verbindungen durchlässt.
- Es muss eine aktive und richtig konfigurierte Powershell-Session am Laufen sein.
Um den Start mit dem Remoting möglichst schnell zu schaffen, hat das Powershell-Team bei Microsoft ein eigenes Cmdlet geschrieben: Enable-PSRemoting. Es übernimmt die Konfigurationsaufgaben dazu und wickelt sie automatisch ab. Diese Aktionen müssen allerdings auf dem System stattfinden, das man über das Powershell Remoting ansprechen möchte(sprich das entfernte System) – nicht über das System, von dem aus das Powershell Remoting angestoßen wird (sprich das lokale System).
Um Enable-PSRemoting ausführen zu können, muss man Administratorrechte auf dem betreffenden System haben. Ab den Betriebssystemen Windows Vista und Windows Server 2008 funktioniert das mit einem rechten Mausklick auf das Powershell-Icon und dann mit dem Punkt „als Administrator ausführen“. Wer beim Aufruf des Cmdlets auch gleich den Parameter -Force mit übergibt, der braucht keine weiteren Zustimmungen für jeden der Konfigurationsschritte abgeben. Weitere Informationen zu diesem Cmdlet stehen über den folgenden Befehl zur Verfügung:
Get-Help Enable-PSRemoting
Die einfachste Möglichkeit, um sich über die Powershell mit einem entfernten System zu verbinden, ist das Eingeben des Cmdlets Enter-PSSession. Der Standard-Parameter für dieses Cmdlet lautet -ComputerName. Daher muss man den Parameter-Namen nicht eingeben, sondern nur den betreffenden Computernamen. Um sich zum Beispiel mit einem System zu verbinden, das rigel heißt, ist folgender Befehl nötig:
PS C:\> Enter-PSSession rigel
Die ersten Zeichen in dieser Befehlszeile verdeutlichen den „Kommandoprompt“ – das ist nicht Bestandteil des eigentlichen Befehls. Hat der Administrator eine Remote-Session gestartet, ändert sich der Kommandoprompt: Es wird der betreffenden Computername (auf dem die Powershell-Kommandos ausgeführt werden) in eckigen Klammern vorangestellt, wie etwa bei
[rigel]: PS C:\>
So würde also der Kommandoprompt aussehen, wenn er von einem entfernten System kommt. Ist erst einmal die Verbindung zu dem entfernten System etabliert, werden die Powershell-Befehle dort ausgeführt. Zum Beispiel würde der folgende Befehl
[rigel]: PS C:\> Get-ChildItem C:\
auf dem entfernten System (namens rigel) ausgeführt. Daher würde man als Ausgabe alle Dateien und Verzeichnisse auf dem C-Laufwerk des entfernten Computers (rigel) aufgelistet bekommen. Um diese remote Powershell-Sitzung zu beenden, kann man das Cmdlet Exit-PSSession verwenden, wie etwa im folgenden Kommando zu sehen ist:
[rigel]: PS C:\> Exit-PSSession
Richtig interessant wird das Arbeiten mit dem Powershell Remoting aber erst, wenn man einen sogenannten Scriptblock – also einen ganzen Block von Powershell-Befehlen – auf einem entfernten System ausführen kann. Ein derartiger Block von Anweisungen wird von geschweiften Klammern eingerahmt. Dazu gibt es das Cmdlet Invoke-Command mit dem Parameter -Computername.
Ein Beispiel dazu zeigt die Abbildung 1. Hier wird das Cmdlet Invoke-Command verwendet, um das Kommando Get-ChildItem auf einem entfernten Computer auszuführen. In dieser Abbildung ist auch zu sehen, dass dabei nicht zuerst mit dem Cmdlet Enter-PSSession die Verbindung zu einem entfernten System aufgebaut wird, ehe es an das Ausführen des Scriptblocks geht. Der Einsatz von Enter-PSSession und von Invoke-Command sind zwei verschiedene Wege, um mit entfernten Systemen zu arbeiten.
Der erste Parameter des Cmdlet Invoke-Command ist -ScriptBlock. Damit gibt der Administrator den Code an, der ausgeführt werden soll. In Abbildung 1 wird die Angabe des Parameternamens weg gelassen, denn dieser ist für Invoke-Command optional. Dagegen ist der Parameter -ComputerName nötig, um den gewünschten entfernten Computer spezifizieren zu können. Wie die Ausgabe des Cmdlet Get-ChildItem zeigt, fügt die Powershell den Namen des entfernten Computers in der Spalte PSComputerName hinzu. Damit wird die Ausgabe besser verständlich.
Scriptblöcke auf mehreren entfernten Computer laufen lassen
Die hohe Kunst des Powershell Remoting zeigt sich aber erst so richtig, wenn ein Scriptblock auf mehreren entfernten Systemen ausgeführt werden soll. Dabei handelt es sich dann um eine Konstellation nach dem Motto „1 zu viele“ (manche bezeichnen das auch als Fan-Out). Auch wenn zum Beispiel das Cmdlet Invoke-Command den Parameter -ComputerName mit nur einem Computernamen bisher gezeigt wurde (siehe Abbildung 1), so beherrscht es auch den Umgang mit mehreren Systembezeichnungen.
Zum Beispiel führt das folgende Kommando (Vorsicht, es muss auf einer Zeile eingegeben werden, die Zeilenumbrüche hier sind nur wegen der besseren Lesbarkeit eingefügt; das gilt auch für alle weiteren Kommandos, die über mehr Zeilen hier angezeigt werden)
PS C:\> Invoke-Command
{ Get-ChildItem env:co* }
-Computer titan,rigel
Den Scriptblock mit { Get-ChildItem env:co* } auf zwei entfernten Computern aus. Wie in Abbildung 1 wird dann in der Spalte für die PSComputerName in der Ausgabe dann die beiden Computernamen enthalten sein.
Der Einsatz von Scriptblöcken im Hintergrund
Mit der Powershell 2.0 besteht auch die Möglichkeit, Background Jobs (als eine Art der Verarbeitung im Hintergrund) abzusetzen. Das ist besonders dann von Nutzen, wenn ein Befehl lange braucht, um seine Arbeiten zu erledigen. Um einen Hintergrund-Job auf dem lokalen System zu starten, gibt es das Cmdlet Start-Job. Allerdings besitzt dieses Cmdlet keinen Parameter wie -ComputerName, um damit auch einen Background-Job auf einem entfernten System anzustoßen.
Dafür muss der Administrator auf das Cmdlet Invoke-Command zurück greifen. Dazu ist dann der Parameter -AsJob nötig. Zum Beispiel kann man einen Befehl, wie er in Abbildung 2 als erstes Kommando zu sehen ist, absetzen. Damit wird der Scriptblock (also der Inhalt in den geschweiften Klammern) auf dem entfernten System namens titan als Hintergrund-Job abgearbeitet.
Wer einen Befehl wie diesen eingibt, bei dem wird das Kommandozeilen-Prompt auch sofort wieder erscheinen, wenn die Powershell den Scriptblock an das entfernte System übermittelt hat. Dann wird die Kontrolle über das System sofort wieder an den Administrator gegeben. Dabei wird auch noch eine Warnmeldung ausgegeben, weil das ausgeführte Kommando von der Ausgabe her ein breiteres Konsolenfenster benötigt hätte. Daher wurde die eine Spalte nicht angezeigt.
Die Spalten für die ID und den Namen helfen bei der Identifizierung des Background-Jobs. Die Spalte mit dem State gibt Auskunft, ob der Job noch läuft, ob er pausiert oder ob er fertig ist. In der Spalte „HasMoreData“ ist verzeichnet, ob alle angegebenen Daten von dem Job ermittelt wurden, oder ob er Job noch mehr Daten holen muss.
Um festzustellen, ob ein Hintergrund-Job fertig ist, kann der Administrator das Cmdlet Get-Job einsetzen (das ist als zweites Kommando in der Abbildung 2 zu sehen). Gibt der Systembetreuer keine Parameter mehr mit an, prüft Get-Jobs die Stati aller Jobs, die in der aktuellen Powershell-Session gestartet wurden. Wer viele Jobs laufen hat, der kann über die Parameter wie -Id oder-Name angeben, über welche Jobs er die Informationen haben möchte. Ist ein Hintergrund-Job fertig, so findet man als Eintrag in der Spalte Status ein „completed“.
Um die Ergebnisse eine Background-Jobs zu bekommen, eignet sich das Cmdlet Receive-Job. Wie schon Get-Job gibt auch Receive-Job die Ausgabe von allen Jobs zurück, die in der aktuellen Session gestartet wurden. Auch hier kann man über die Angabe der bereits genannten Parameter einschränken, von welchen Jobs man die Infos bekommen möchte.
Zum Beispiel verwendet das letzte Kommando, das in Abbildung 2 zu sehen ist, den Parameter –Id. Damit wird die Ausgabe geliefert, die zum Job mit der Kennung 9 gehört. Auch hier ist die Parameterbezeichnung -Id weggefallen – das ist auch hier zulässig. In Abbildung 3 (auf dernächsten Seite) ist das Ende der Ausgabe zu sehen, die von diesem entfernten Hintergrund-Job geliefert wurde.
Erzeugen von Powershell-Sitzungen
In den bisher gezeigten Beispielen des Powershell Remotings wurde immer gezeigt, wie der Zugriff auf das Powershell-Prompt auf dem entfernten Computer gelingt und wie man darauf aufbauend Befehle auf den entfernten Systemen ausführen kann. Was dabei aber noch nicht erwähnt wurde:
Das Powershell Remoting tritt immer im Zusammenhang mit einer Powershell-Session auf. Und unter einer derartigen Session „lebt“ die Powershell sozusagen. Wenn der Administrator ein Powershell-Konsolenfenster öffnet oder wenn er das ISE (Integrated Scripting Environment) der Powershell startet, dann erzeugt er eine Powershell-Session.
Ohne den Einsatz des Powershell Remotings läuft jede Session auf dem lokalen System und alle Sessions sind voneinander unabhängig. Alle vorherigen Beispiele zum Remoting erzeugen temporäre Sessions, die automatisch weggeworfen werden, wenn das Remoting sozusagen fertig ist.
Doch der Administrator ist auch in der Lage, Istanzen einer remoten Session zu erzeugen und sie später wiederzuverwenden. Das erweist sich in der Praxis als wesentlich effizienter – vor allem, wenn man den Zugriff auf die entfernten Systeme mehr als einmal benötigt.
Um neue Sessions zu erzeugen, bietet die Powershell das Cmdlet New-PSSession und das verfügt noch über den Parameter -ComputerName. Auch dabei handelt es sich um eine Parameter-Bezeichnung, die man bei seinen Befehlen weglassen darf. Dazu das folgende Beispiel:
C:\> $sessions =
New-PSSession phineas,ferb,perry
Es erzeugt drei Sessions auf den drei Computern (mit den Namen phineas, ferb und perry). Der Administrator kann sich die Sessions anzeigen lassen, dazu muss er lediglich die Variable $sessions ausgeben und zwar mit:
$sessions
am Beginn der Kommandozeile und gefolgt von einem Return. Der Parameter -Session des Cmdlets Invoke-Command unterstützt die Session-Objekte, die von New-PSSession angelegt wurden. Daher kann der Systembetreuer ein Kommando ausführen wie:
C:\> Invoke-Command { Get-ChildItem }
-session $sessions
Dieses Kommando führt das Cmdlet Get-ChildItem auf phineas, ferb und perry aus, beendet aber nicht die Verbindungen. Man kann den Parameter -AsJob mit angeben, um das Kommando im Hintergrund auszuführen, wie etwa im folgenden Befehl:
C:\> Invoke-Command { Get-ChildItem }
-session $sessions -asjob
Dann ist der Administrator in der Lage, die Cmdlets Get-Job und Receive-Job einzusetzen, um den Zustand der Jobs abzufragen und um die Ausgabe der Jobs entgegen zu nehmen.