Archiv der Kategorie: PowerShell lernen

Kleine Beispiele, die sich für Schulungen eignen

PowerShell-Know how: Die Rolle der psbase-Eigenschaft

Jedes PowerShell-Objekt besitzt eine psobject– und eine psbase-Property. Beide sind also immer da, werden aber relativ selten für irgendwelche Abfragen benötigt. Während psobject das Objekt beschreibt, das von PowerShell für jedes Objekt als eine Art „Rahmenobjekt“ angelegt wird (auch „Adapter“ genannt, da hier das klassische Adapter-Entwurfsmuster angewendet wird), erlaubt psbase eine Abfrage der Members des „eingebauten“ Objekts.

Und wann braucht man das?

Zum Beispiel, wenn man die Members der (abstrakten) Array-Klasse erhalten will, auf der PowerShell-Arrays basieren.

Das gilt auch für Listen aller Art.

Die Rückgabe ist allerdings kein RuntimeType-Objekt, sondern ein PsObject-Objekt.

psobject und psbase sind elementare Bestandteile des PowerShell-Typssystems, das auf dem .NET-Typsystem aufsetzt und zu mehr Flexibilität führen soll (das Thema dynamisches Typisieren kam durch Programmiersprachen wie Ruby und Python damals gerade erst in Mode). Leider aber auch zu etwas Verwirrung (da nehme ich mich selber nicht aus;). Eine gute Zusammenfassung gibt der „Vater“ der PowerShell, Jeffrey Snover, in einem Blogeintrag aus dem Jahr 2006 (!):

PowerShell für Anfänger – die praktische psobject-Property

Es ist eine der größeren Herausforderungen für viele PowerShell-Anfänger den Unterschiedzwischen Select-Object und Where-Object zu verstehen. Das liegt weniger an der Namensgebung, sondern in erster Linie daran, dass am Anfang überhaupt nicht klar ist, was es konkret bedeutet, dass Ausgaben immer aus „Objekten“ bestehen.

Die nächste Hürde besteht darin, den Unterschied zwischen dem Namen einer Eigenschaft und ihrem Wert zu verstehen.

Ein

gibt vom aktuellen PowerShell-Prozess alle Eigenschaften mit ihren Werten zurück, in deren Name das Wort „Time“ enthalten ist.

Wie aber müsste die Abfrage lauten, wenn alle Eigenschaften ausgegeben werden sollen, die z.B. keinen Wert besitzen?

Anders, als man es vielleicht vermuten würde, ist eine solche Abfrage mit Where-Object zunächst nicht möglich. In der vereinfachten Syntax muss der linke Vergleichswert immer der Name einer Property sein.

Ein

funktioniert nicht, da für den Property-Parameter kein Platzhalter eingesetzt werden darf (das musste ich allerdings erst noch einmal selber überprüfen;).

Möchte man für eine Abfrage auf die „Beschaffenheit“ (Medaten) eines Objekts zugreifen, also z.B. auf die Namen, Typen und Werte der Properties, kommt die „unsichtbare“ psobject-Property ins Spiel, über die jedes (!) Objekt verfügt. Siegibt das „PowerShell-Objekt“ zurück. Das ist jenes Objekt, von dem sich jedes von der Powershell angelegte Objekt ableitet.

Das PowerShell-Objekt besitzt folgende Properties:

>BaseObject

>IntermediateBaseObject

>Members

>Method

>Properties

>TypeNames

Der folgende Befehl gibt alle Properties des Process-Objekts zurück.

Diesselben Informationen liefert zwar auch Get-Member, in diesem Fall lassen sie sich aber flexibler weiterverarbeiten.

Die folgende Abfrage gibt die Namen und (damit die Ausgabe nicht so „nackt“ ist) auch die Typen aller Eigenschaften des PowerShell-Prozess-Objekts zurück, die keinen Wert besitzen.

Abb. Dank der psobject-Property ist auch ein Filtern nach den Namen und Werten von Eigenschaften möglich.

Praktisch ist diese Technik bei Abfragen mit Get-WmiObject, da sichd die zahlreichen Eigenschaften, die mit __ beginnen, ausblenden lassen.

Auch wenn der Tippaufwand für diese Abfrage insgesamt doch recht groß ist, werden endlich nur jene Properties ausgeben, die keine Spezial-WMI-Properties sind, und die einen Wert besitzen.

Fazit: Bei der PowerShell besitzt jedes Objekt eine psobject-Eigenschaft. Sie liefert sozusagen das „Rahmenobjekt“, in das jedes Objekt eingebaut wird. Mit seiner properties-Eigenschaft lassen sich neben den Namen auch die Werte von Eigenschaften abfragen was in manchen Situationen ganz praktisch sein kann. Auch wenn man diese Eigenschaft nie verwenden wird, sollte man wissen, dass es sie gibt.

PowerShell für Anfänger – Wie liest man die Parametersyntax eines Cmdlets?

Jedes PowerShell-Command besitzt eine Reihe von Parametern, die immer in einer einheitlichen Schreibweise als Teil der „Syntax“ ausgegeben werden (z.B. per Get-Command und dem Syntax-Parameter).

Was mir am Anfang in Schulungen etwas schwer fiel zu erklären war, was die eckigen Kammern bei den Parameternamen zu bedeuten haben. Mal gibt es welche, mal gibt es sie nicht.

Der Hintergrund ist natürlich der Umstand, dass es bei den meisten Commands Pflichtparameter gibt, der Name eines Parameters aber auch entfallen kann, wenn es ein Positionsparameter ist.

Hier die (eigentlich sehr einfache) Regel:

>Ist nur der Name des Parameters in eckige Klammern gesetzt, ist der Parameter ein Pflichtparameter und ein Positonsparameter – sein Name kann daher entfallen.

>ist der gesamte Parameter in eckige Klammen gesetzt, ist der Parameter kein Pflichtparameter und kann komplett entfallen.

>Die eckigen Klammern am Ende des Datentyps besitzen eine andere Bedeutung. Sie geben an, dass auch mehrere Parameterwerte per Komma getrennt übergeben werden können.

Eine Frage zum Verständnis: Wie viele Pflichtparameter besitzt das ForEach-Object-Cmdlet und darf der Name des Process-Parameters weggelassen werden? Die Auflösung erfolgt in Kürze.

Die Antwort: Einer und Ja. Es gibt aber glaube niemanden, der jemals den Process-Parameter hingeschrieben hat;)

PowerShell-Know how als Teil der Windows-Problemlöser

Auf diesen Blog-Eintrag wollte ich schon seit Jahren hinweisen, da ich ihn sehr gut finde:

https://chentiangemalc.wordpress.com/2011/05/08/windows-7-can-teach-you-powershellinbuilt-wealth-of-scripts/

Der Autor hat sich die Mühe gemacht, die vielen PowerShell-Skripte, die unter der Haube der zahlreichen Diagnosehilfen von Windows ihren Dienst verrichten, aufzulisten und ihren Inhalt zu untersuchen.

Auch wenn, wie es PowerShell-Experte Jeffrey Hicks es in einem Kommentar korrekt anmerkt, einige (oder eher viele?) der vorgestellten Techniken veraltet bzw. nicht ganz optimal sind, zum Lernen der verschiedenen PowerShell-Techniken sind die Skripts dann doch gut geeignet.

Auf alle Fälle ist es erstaunlich, welche Fülle an PowerShell-Know how abseits der offiziellen Module bereits bei Windows 7 im Windows-Verzeichnis dabei war.

Seltsame PowerShell-Phänome (Teil 45)

Manchmal kann das Arbeiten mit der PowerShell nervig oder faszinierend sein. Je nachdem, ob eine Anforderung unbedingt umsetzen möchte, oder man viel Zeit hat sich mit besonderen „Phänomen“ zu beschäftigen. Das folgende, eigentlich ganz simple Phänom befindet sich bei mir im Moment noch in der Kategorie ungelöst.

Ausgangspunkt ist das Abfragen der Inhalte einer PowerPoint-Datei über die DocumentFormat.OpenXml-Assembly aus dem Open XML SDK.

Die Anforderung ist die Ausgabe aller Slides bzw. deren Ids. Auch wenn die folgende Vorgehensweise nicht die Richtige ist, sollte doch ein konsistentes Verhalten resultieren.

Der folgende Befehl sollte alle „Abkömmlinge“ vom Typ „SlideId“ holen

Die Abfrage gibt aber nichts zurück. Es funktioniert, wenn anstelle des -eq-Operators der -match- oder -like-Operator verwendet wird:

Die Rückgabe besteht aus einem Objekt vom Typ SlideIdList und mehreren Objekten vom Typ SlideId. Irgendetwas scheint an dem Vergleich nicht zu stimmen.

Eigentlich sollte Where{} nur die Objekte liefern, die vom Typ „SlideId“ sind. Da es aber auch ein Objekt gibt, das vom Typ „SlideIdList“ ist, funktioniert der Vergleich mit dem eq-Operator nicht und es werden beim Vergleich mit „SlideId“ keine Objekte zurückgegeben.

Kurios ist, dass der folgende Vergleich funktioniert:

Diese Abfrage gibt für jeden Typnamen = „SlideId“ mit dem eq-Operator ein $true zurück. Es muss also „irgendwie“ mit dem Umstand zu tun haben, dass das erste Objekt vom Typ SlideIdList ist, die übrigen vom Typ SlideId und mit dem, was durch die Array-Konvertierung der Rückgabe von Descendants() (eine generische Collection) entstanden ist.

Da ich keine Lust habe, einen schönen Sonntagnachmittag mit der Lösung zu verbringen, gebe ich an dieser Stelle auf und bin gespannt, wann ich eine Erklärung für dieses (im Grunde natürlich vollkommen unwichtige) Phänom erhalte. Apropos unwichtige Kleinigkeit: Hätte sich Clifford Stoll irgendwann Ende der 80er Jahre nicht über eine Abrechnungsdifferenz von wenigen Cents gewundert, wäre er nicht einem der größten Hacker-Einbrüche in den USA auf die Spur gekommen.

PowerShell lernen – Alle Exe-Dateien finden

Wer die PowerShell muss sich u.a. daran gewöhnen, dass als Parameterwert immer auch das Ergebnis eines anderes Befehls eingesetzt werden kann.

Aufgabenstellung: Ausgabe aller Exe-Dateien, die mit dem Namen „Fus“ beginnen, und deren Pfade auf der Grundlage der Verzeichnisse in der Path-Umgebungsvariablen.

Schritt 1: So geht es nicht

Der folgende Aufruf wäre denkbar, doch so einfach geht es nicht.

Schritt 2: So geht es

Da die Path-Umgebungsvariable in der Regel mehrere Verzeichnispfade enthält, die per Semikolon getrennt sind, muss dies beim Aufruf berücksichtigt werden.

Schritt 3: Alles zusammen ausgeben

Jetzt werden alle Dateien aufgelistet, aber pro Verzeichnis. Möchte man alle Dateien in einer Liste erhalten, muss z.B. ein Select-Object angehängt werden. Dabei wird auch festgelegt, dass pro Datei der vollständige Pfad ausgegeben werden soll.