Windows PowerShell

Was the Heck $ _ ist?

Don Jones

W Ann ich bin ein Windows PowerShell-Klasse oder einer Konferenz Vortrag ausführen, liebe ich um trot out eine Einzeiler wie folgt:

Import-CSV c:\users.csv | ForEach-Object {New QADUser - Logonname $ _.username - Name $ _.Name}

Tatsächlich auf eine aktuelle Konferenz TechMentor ich meine Sitzungen, mit etwas gestartet, und ich eine längere Version in einer Rede bei Tech-Ed verwendet. Diese Einzeiler importiert eine Liste der Benutzerinformationen aus einer CSV-Datei, und diese Informationen in neue Benutzer in Active Directory werden aktiviert. Es ist eine hervorragende Demonstration, da es veranschaulicht, dass Windows PowerShell sehr viel erreichen können, indem Sie Befehle direkt ausführen, anstatt Programm komplexe Skripts zu müssen.

Lange nachdem ich auf andere Demos verschoben haben, besteht eine Sache, die noch Personen Augen Kreuz stellt jedoch: $_. Im praktischen Klassen sehen ich Kursteilnehmer versuchen mit $ _on der Befehlszeile ohne viel Glück wiederzugeben. In online Diskussionsforen sehen ich Fragen dazu, Benutzer versuchen, zu verstehen, was es bedeutet. Glücklicherweise ist die Antwort einfach, wenn nicht ganz einfach.

Übergeben Sie Buck den... er, Object

Denken Sie daran, dass alles, was in Windows PowerShell ein Objekt ist. In der Regel können Sie diese Tatsache ignorieren die schön ist, weil Objekte zwischen die Probleme bei der Software-Entwickler sind, die problemlos verwirrende Erläuterungen vornehmen können. Ich werde versuchen, die am häufigsten verwirrend Aspekte mit diesem einfachen Beispiel zu vermeiden:

Get-Service

Dieses Cmdlet erzeugt eine Reihe von Serviceobjekten. Das bedeutet lediglich, dass Sie Sie an anderen Cmdlets leiten können, die Serviceobjekte als Eingabe akzeptieren:

Get-Service | Stop-Service

Jedoch wird nicht ausgeführt, es sei denn, Sie interessieren sich jeder Dienst wird beendet, auf dem Computer--dem wird wahrscheinlich abstürzen es, wenn nicht unerwartet beendet. Im Grunde kann Stop-Service Serviceobjekte, unter anderem als Eingabe akzeptieren, informiert Sie, welche Dienste zu beenden. Einige Cmdlets sind Allgemein weitere akzeptieren und kann fast jede Art von Objekt als Eingabe annehmen:

Get-Service | Sort-Object-Name
Get-Prozess | Sort-Objektname

In diesen Beispielen wird Sort-Object perfekt gerne mit entweder Serviceobjekte arbeiten oder verarbeiten Objekte Ablegen der Dateien in der Reihenfolge von beliebigen Objekteigenschaft--in beiden Fällen die Name-Eigenschaft--, die Sie angeben.

Technisch gesehen, Name wird durch des Cmdlets des - Eigenschaft Parameter akzeptiert wird bedeutet, dass ich eine vollständige Befehlszeile wie die folgende geschrieben haben kann:

Get-Process | Sort-Object-Name-Eigenschaft

Das heißt, "Diese Objekte übernehmen und sortieren Sie diese auf die Eigenschaft Name." 
Jedes Cmdlet besitzt einen oder mehrere Parameter, die das Cmdlet-Verhalten in irgendeiner Weise anpassen. Sort-Object, hat zum Beispiel einen weiteren Parameter, mit dem ich die Reihenfolge der Sortierung umkehren kann:

Get-Process | Sort-Object - Eigenschaft Name - absteigend

Unabhängig davon, dauert Sort-Object die input-Objekte, Ablegen der Dateien in einer anderen Reihenfolge und die gleichen Objekte in Ihre neue Sequenz Ausgabe.

Super-Parameter: Scriptblocks

Einige besonders leistungsfähige Cmdlets können gesamte Skripts, die Ihnen als Parameter angegeben haben. Windows PowerShell in der Regel verweist auf diese als Scriptblocks, da – nun, da jeweils einen Block von Skriptcode ist. Je häufiger diese bestehen aus einen Block von Befehlen anstelle eines Skripts, die im Zusammenhang mit detaillierten Programmierung, aber Sie können fast alle Elemente in einem Skriptblock ablegen.

Eine solche Cmdlet ist Where-Object. Er akzeptiert als Eingabe eine Reihe von Objekten--ein Objekt beliebigen Typs geschieht-- und führt dann einen Skriptblock einmal für jedes Objekt, das eingegeben wurde.

Wenn der Skriptblock den booleschen Wert True ausgibt, dann das geleitet-Objekt wird geleitet aus; Wenn False der Skriptblock ausgegeben, das geleitet Objekt verworfen. Auf diese Weise können Sie die WHERE-Object für Filterobjekte, die auf bestimmte Kriterien basieren. Beispiele:

Get-WmiObject-Klasse Win32_Service | Where-Object-Filterscript {$ _.State - Eq "ausführen"}

Ist die $ _ erneut. Tatsächlich, beide-Klasse und - Filterscript-Parameter sind mit Feldern fester Breite, d. h., solange Sie einen Wert in der ersten Position übergeben, können Sie den tatsächlichen Parameternamen nicht benötigen. Das bedeutet, dass Sie in der Regel wie folgt als Beispiel sehen werden:

Get-WmiObject Win32_Service | Where-Object {$ _.State - Eq "ausführen"}

Aber es ist dasselbe. Die geschweiften Klammern sind die Shell Möglichkeit der einschließenden ein Skriptblock standardisiert des. In diesem Fall wird der Skriptblock nicht viel eines Skripts überhaupt; es ist ein relativ einfaches Vergleich. Und, kommt $ _ in: Denken Sie daran, dass der Skriptblock einmal für jedes Objekt geleitet-in ausgeführt wird. Wenn der Skriptblock ausgeführt wird, wird durch das aktuelle Eingabeobjekt $ _ ersetzt. Anders ausgedrückt, ist $ _ ein Platzhalter für das aktuelle Pipelineobjekt. $ _ ermöglicht es Ihnen, vergleichen Sie dieses Objekt Eigenschaften--z. B. die State-Eigenschaft--mit Werten wie z. B. "Ausführen".

Was ist ein Name?

Ich habe immer dachte, dass $ _ ein ungerade Stück Syntax. Zu verschiedenen Zeiten habe ich dachte, ein einfacher lesbaren Namen wie $ geleitet-in oder Inputobject $ u. u. sinnvoller sein, dass $ _ mindestens einfach einzugeben ist. Ich bin sagte, dass $ _ seinen Namen, haben da der Unterstrich ein Pipeline-Zeichen (| ähnelt) auf seiner Seite liegenden sagen, dass er enthält alles, was an die Pipeline gesendet wurde.

Die Person, die mich dies mitgeteilt wurde in der Lage, solche Dinge wissen und war ziemlich schwerwiegende-- jedoch immer noch meine Abschnitt ist mit etwas tugged-auf. Ich möchte, für mich $ _ eine leere, wie in "Füllung in die leere" dar Es ist eine leere, die automatisch von der Shell ausgefüllt ruft, wenn der Skriptblock ausgeführt wird.

Und darin liegt den Schlüssel, der meisten Benutzer verwechseln abruft: $ _ ist gültiger und verwendbarer nur an bestimmten Speicherorten, wo Windows PowerShell ist explizit dafür gesucht und wird vorbereitet, um es durch einige Eingabeobjekt ersetzen. Solche zentral wird der Skriptblock für Where-Object und ForEach-Object-Cmdlets (z. B. der am Anfang dieses Artikels) verwendet.

Eine andere Stelle befindet sich innerhalb der PROCESS-Block für bestimmte Arten von Windows PowerShell-Funktionen. Aber natürlich, Sie können nicht gerade $ _.Status in der Shell-Befehlszeile eingeben und davon ausgehen, dass es funktioniert. Die Shell wird nicht gesucht $ _ zu diesem Zeitpunkt so $ _ durch nichts ersetzt abrufen nicht; es ist im Wesentlichen ein nicht definierter Wert.

Schachtelt: Nicht nur für Vögel

Eine andere verwirrende Situation kann auftreten, wenn Sie geschachtelte Scriptblocks haben. Beachten Sie in diesem Beispiel, das liest eine Liste von Computernamen aus einer Datei (ein Name pro Zeile) und versucht, diese alle mithilfe von Windows-Verwaltungsinstrumentation (WMI) neu starten:

Get-Content c:\names.txt | ForEach-Object {Get-WmiObject - Computername $ _ - Klasse Win32_OperatingSystem | ForEach-Object {$_.Reboot()}}

Dadurch erhalten ein bisschen leichter zu lesen, wenn ich verhindern, behandeln dies als eine einzige Befehlszeile, und stattdessen einige Menschen-freundliche Formatierung anwenden:

Get-Content c:\names.txt | ForEach-Object {Get-WmiObject - Computername $ _ - Klasse Win32_OperatingSystem | ForEach-Object {$_.Reboot()}}

 

Hier ist es einfacher, es gibt geschachtelten ForEach-Object-Cmdlets herauszufinden. Jede hat einen Skriptblock, und jeder Skriptblock verwendet $ _. Der Trick dabei ist, dass die $ _ tatsächlich seine Bedeutung im Laufe dieser Befehlszeile ändert, aber immer enthält eines der Objekte, die an die ForEach-Object-Cmdlet geleitet wurde.

Also die erste ForEach-Object empfängt Computernamen von Get-Content; aus diesem Grund enthält die erste $ _ Computernamen, die an den - Computername-Parameter angegeben wird, sind.

Zweite ForEach-Object empfängt Eingaben von Get-WmiObject, so dass die $ _ dieser WMI-Objekte--enthält insbesondere Instanzen der Klasse Win32_OperatingSystem ab, die eine bequeme Methode Reboot() verfügen.

Hier also ein Trick, um herauszufinden, welche $ _ enthält: Denken Sie daran, dass Objekte, die durch das nächste Cmdlet links von der Befehlszeile erzeugt immer enthalten wird.

Wenn Sie solchen tief geschachtelte Situationen abrufen, die Möglichkeit, für die Ablaufverfolgung rückwärts ermöglicht es Ihnen, herauszufinden, was auf so einfach geht.

Es ist immer die Punkte

Ich habe immer das Gefühl, dass der Unterschied zwischen einer Windows PowerShell-Newbie und ein Experte nicht oder alle verfügbaren Befehl einprägen, komplexe Skripts schreiben. Stattdessen ist es aufbauten beherrschen einige "fallen" oder ungerade Teile-Syntax, die im Lieferumfang enthalten alle Shell oder Sprache ist. $ _ ist eine dieser. Es ist schwierig, herauszufinden, indem Sie welche $ _ ist betrachten.

Doch nun, da Sie wissen, können Sie beginnen, es in mehrere der eigene Befehle verwenden. Wie Sie tun, Sie es--master müssen und verschieben, die viel näher zu einer

Windows PowerShell-Experte.

 

Don Jones ist eine von der Nation erfahrene Windows PowerShell Schulungsleiter und Schreiber. He Blogs wöchentlichen Windows PowerShell-Tipps zur ConcentratedTech.com; Sie können auch kontaktieren Sie ihn oder Fragen ihm dort .