PowerShell: Objekte, Objekteigenschaften und –Methoden, Objektverarbeitung – Part 6
3.7 Objekte, Objekteigenschaften und –Methoden, Objektverarbeitung
Die wohl revolutionärste Idee, die den Einzug in PowerShell gefunden hat, ist die Verwendung von Objekten. Fast alles in der PowerShell wird durch (.Net) Objekte repräsentiert. Was bedeutet das genau? Ein Beispiel sollte helfen… Sowohl in der CMD wie auch in der PS kann der Befehl „dir“ zur Auflistung von Verzeichnisinhalten verwendet werden (natürlich ist das in der PowerShell nur ein Alias…). Die Ausgabe des Befehls auf dem Bildschirm kann ähnlich oder gar identisch sein. Innerhalb der CMD kann höchstens mit Hilfe der For-Schleife die Ausgabe noch etwas verarbeitet werden. Die Elemente sind jedoch reiner Text (Strings). Mit normalen Mitteln können nur sehr schwer weitere Informationen über die aufgelisteten Dateien eingeholt werden (meist sind externe Werkzeuge notwendig). Soll z.B. das Datum der letzten Änderung einer Datei oder eines Verzeichnisses ermittelt werden, müssen komplizierte und vor Allem schwer lesbare Konstrukte verwendet werden, wie z.B. hier:
for /f " usebackq tokens=1" %i in (`dir ^| find /i "Music"`) do echo %i</pre> 21.08.2010
Das könnte noch hingenommen werden, aber was ist mit den Eigenschaften, welche mit Hilfe des Befehls „dir“ gar nicht auf dem Bildschirm angezeigt werden, wie z.B. das Erstellungsdatum? Hmmm, ohne externe Werkzeuge wird das wohl nicht machbar sein…
Die PowerShell verhält sich an dieser Stelle völlig anders. Es wird zwar möglicherweise Ähnliches angezeigt, wie in der CMD, aber es stehen dennoch wesentlich mehr Informationen und Möglichkeiten zur Verfügung. Das geschieht dadurch, weil die PowerShell für jeden Verzeichniseintrag ein Objekt erzeugt…
Exkurs: objektorientiertes Programmieren
Das objektorientierte Programmieren fängt mit einer Klasse an. Eine Klasse beschreibt sog. Eigenschaften und Methoden eines künftigen Objektes. Nehmen wir mal an, wir definieren eine Klasse mit dem Namen „Auto“. Fast jedes Auto braucht Räder (welche wiederum eine andere Klasse sind oder sein können), deren Anzahl oder die Reifenbreite Eigenschaften ist. Eine andere Eigenschaft könnte z.B. die Autofarbe oder die Fahrgeschwindigkeit sein. Fährt ein Auto an, muss Gas gegeben werden, zum Anhalten muss gebremst werden. Dies wären Methoden, die auf das Auto angewendet werden können (beschleunigen, bremsen). Mit der Klasse „Auto“ kann allerdings noch nicht gefahren werden. Die Anzahl der Räder ist nicht bekannt, genauso, wie die Farbe. Um dies tun zu können, muss eine Klasse instanziiert werden: das Auto muss gebaut werden. Eine Instanz einer Klasse hat dann „physikalische“ Räder, die gezählt werden können. Wenn auf das Auto die Methode „Beschleunigen“ angewendet wird, ändert sich auch die Fahrtgeschwindigkeit, genauso, wie beim Bremsen. In der Regel kann also zu jedem Zeit-punkt jede Eigenschaft ermittelt und bestimmte Methoden können angewendet werden. Das Objekt „lebt“ sozusagen…
…, mit all seinen Eigenschaften und Methoden. Zurück zum ursprünglichen Beispiel, diesmal mit einer PS Lösung:
1. $(get-childitem | Where-Object {$_.name -like "music"}).creationtime Montag, 21. Dezember 2009 16:18:49
Somit ist sogar der in einer CMD unmögliche Teil erledigt: es wird das Erstellungsdatum des Eintrages ausgegeben! Zugegebenermaßen sieht die obige Zeile auf den ersten Blick nicht viel besser aus, als das der Fall in der CMD war. Dies wird sich jedoch hoffentlich im Laufe der Zeit ändern.
Wie können die Eigenschaften und Methoden eines PS Objektes angezeigt und verwendet werden? Das Cmdlet Get-Member ist eigens dazu entwickelt, Informationen über einzelne Objekte zu liefern. Je nach Art des Objektes werden natürlich unterschiedliche Informationen ausgegeben, da jede Klasse eigene Eigenschaften und Methoden definiert. Das kann am Beispiel eines Strings veranschaulicht werden:
$MyString = "abc-cde-def" get-member -InputObject $MyString TypeName: System.String Name MemberType Definition ---- ---------- ---------- Clone Method System.Object Clone() CompareTo Method int CompareTo(System.Object value), … Contains Method bool Contains(string value) CopyTo Method System.Void CopyTo(int sourceIndex, … EndsWith Method bool EndsWith(string value), bool En… Equals Method bool Equals(System.Object obj), bool… GetEnumerator Method System.CharEnumerator GetEnumerator(… GetHashCode Method int GetHashCode() GetType Method type GetType() GetTypeCode Method System.TypeCode GetTypeCode() IndexOf Method int IndexOf(char value), int IndexOf… IndexOfAny Method int IndexOfAny(char[] anyOf), int In… Insert Method string Insert(int startIndex, string… IsNormalized Method bool IsNormalized(), bool IsNormaliz… LastIndexOf Method int LastIndexOf(char value), int Las… LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), in… Normalize Method string Normalize(), string Normalize… PadLeft Method string PadLeft(int totalWidth), stri… PadRight Method string PadRight(int totalWidth), str… Remove Method string Remove(int startIndex, int co… Replace Method string Replace(char oldChar, char ne… Split Method string[] Split(Params char[] separat… StartsWith Method bool StartsWith(string value), bool … Substring Method string Substring(int startIndex), st… ToCharArray Method char[] ToCharArray(), char[] ToCharA… ToLower Method string ToLower(), string ToLower(Sys… ToLowerInvariant Method string ToLowerInvariant() ToString Method string ToString(), string ToString(S… ToUpper Method string ToUpper(), string ToUpper(Sys… ToUpperInvariant Method string ToUpperInvariant() Trim Method string Trim(Params char[] trimChars)… TrimEnd Method string TrimEnd(Params char[] trimCha… TrimStart Method string TrimStart(Params char[] trimC… Chars ParameterizedProperty char Chars(int index) {get;} Length Property System.Int32 Length {get;}
In der Spalte „Name“ wird der Name der jeweiligen Eigenschaft oder Methode angezeigt. Die Spalte „MemberType“ informiert darüber, ob der Eintrag eine Methode oder eine Eigenschaft ist (andere MemberTypen sind an der Stelle irrelevant). In der Spalte „Definition“ wird der Typ des Resultats angezeigt, gefolgt von einer möglichen Verwendungssyntax. Der Zugriff auf die Methoden und Eigenschaften eines Objektes erfolgt mit Hilfe sog. Punktnotation. Hinter dem Namen des Objektes wird ein Punkt geschrieben, gefolgt von dem Namen der Methode oder Eigenschaft:
</pre> $MyString.Length 11 <pre>
Wenn eine Methode eines Objektes angewendet werden soll, muss hinter dem Namen der Methode ein Klammerpaar stehen. Für Methoden, welche Argumente brauchen, werden diese innerhalb der Klammern geschrieben:
$MyString.GetHashCode() 732858657 $MyString.Split("-") abc cde def >
Die oben angewendete Methode „Split“ verändert den Wert der Variablen $MyString nicht, sondern gibt das Ergebnis als ein weiteres Objekt aus. Dieses Objekt kann direkt weiter verarbeitet werden oder einer Variablen zugewiesen werden. Soll das Objekt direkt weiter verarbeitet werden, ohne eine zusätzliche Variable erzeugen zu wollen, geschieht das meistens mit Hilfe der sog. Pipeline. Der Begriff Pipeline ist wesentlich älter als die PowerShell. Pipelines werden in fast jeder Shell verwendet, so auch in der CMD. Etwas „durch“ die Pipeline zu schicken bedeutet einfach, dass die Ergebnisse eines Befehls direkt an einen anderen Befehl übergeben werden. In der CMD kann das z.B. so aussehen:
dir | sort /R
Die Ausgabe des Befehls „dir“ wird über die Pipeline an den Befehl „sort“ weiter geleitet. Als Resultat erscheint in diesem Fall der Inhalt des aktuellen Verzeichnisses, absteigend sortiert. Das Resultat ist hier aber ebenfalls reiner Text, so wie auch beim Befehl „dir“. In der PowerShell wird das Ergebnis eines Befehls, also ein Objekt, durch die Pipeline geschickt und an einen anderen Befehl übergeben, ohne sein Wesen als Objekt zu verlieren! Das heißt, auch hinter der Pipeline kann auf Eigenschaften und Methoden zugegriffen werden:
dir | Where-Object {$_.creationtime -gt "01.06.2010"} | Foreach-Object {$_.lastaccesstime} Mittwoch, 15. September 2010 19:20:02 Dienstag, 19. Januar 2010 20:16:13 Sonntag, 18. April 2010 11:06:40 Dienstag, 23. Februar 2010 13:43:18 Mittwoch, 1. Dezember 2010 09:03:52 Donnerstag, 14. Oktober 2010 09:39:37
Im diesem Beispiel listet der „dir“ Befehl (Alias für Get-ChildItem in der PowerShell) den Inhalt des aktuellen Verzeichnisses. Das Ergebnis von 17 Einträgen wird über die Pipeline auf den Befehl Where-Object gesendet. Das Cmdlet Where-Object bietet unter anderem die Möglichkeit, aus einer Sammlung von Objekten diejenigen zu wählen, deren Eigenschaften bestimmten Kriterien entsprechen. Wenn, wie in diesem Beispiel, mehrere Objekte durch die Pipeline geschickt werden, werden sie durch den Befehl hinter der Pipeline nacheinander abgearbeitet. In diesem Konstrukt repräsentiert die Variable $_ das jeweils gerade bearbeitete Objekt. Für jeden Eintrag in dem aktuellen Verzeichnis wird also nach der ersten Pipeline geprüft, ob das Erstellungsdatum ($_.creationtime) größer ist (-gt = grater then, siehe Kapitel 3.9.3), als 01.06.2010. Dieser Schritt reduziert die ursprüngliche Anzahl von Einträgen auf diejenigen, welche die genannte Bedingung erfüllen und sendet das Ergebnis (immerhin noch 6 Einträge) über eine weitere Pipeline an das Cmdlet Foreach-Object. Dieses Cmdlet erlaubt es, für jedes übergebene Objekt die Aktion in den geschweiften Klammern auszuführen. In diesem Fall ist das die Ausgabe der Eigenschaft „lastaccesstime“, also die Zeit des letzten Zugriffes auf den jeweiligen Eintrag im Dateisystem.
Zurück zu Part 5 – Befehle = CMDlets, Aliase, externe Befehle, PSSnapins und Hilfe
Weiter zu Part 7 – Datentypen allgemein
Zur Übersicht aller Artikel dieser Windows PowerShell Blogserie.