PowerShell-Grundlagen: Benutzerdefinierte Objekte

Windows PowerShell ist eine Befehls-Shell-Umgebung, die objektorientiertes Skripting auf der Grundlage des Microsoft .NET Framework unterstützt. Ihr Herzstück ist das PowerShell-Cmdlet, ein leichtgewichtiger Befehl, der eine bestimmte Aktion ausführt und dabei ein .NET-Objekt zurückgibt. Mit PowerShell können Sie mithilfe von Cmdlets auf eine Vielzahl von Systemen zugreifen und zahlreiche Aufgaben für diese Systeme ausführen. Die Cmdlets allein reichen jedoch nicht immer aus, um bestimmte Aktionen auszuführen. Für diese Aktionen müssen Sie oft eigene Objekte auf der Grundlage der .NET-Klassen erstellen. Ein Typ von .NET-Objekten, den Sie erstellen können, ist das benutzerdefinierte Objekt. Mit einem benutzerdefinierten Objekt können Sie die Datentypen, die diesem Objekt zugewiesen sind, und die Aktionen, die es ausführen kann, definieren. Nachdem Sie verstanden haben, wie ein benutzerdefiniertes Objekt erstellt wird, verfügen Sie über ein leistungsfähiges Tool zum Erstellen von Skripts, mit denen die bereits beträchtliche Reichweite von PowerShell erweitert werden kann.

Beachten Sie, dass das .NET Framework und die objektorientierte Programmierung komplexe Themen sind, die den Rahmen dieses Artikels bei weitem sprengen würden. Um die objektorientierte Natur von PowerShell voll zu schätzen, kann es hilfreich sein, zumindest ein Grundverständnis dieser Konzepte zu haben. Weitere Informationen über das .NET Framework finden Sie im MSDN-Artikel „Overview of the .NET Framework“. Eine Einführung in die objektorientierte Programmierung finden Sie im MSDN-Artikel „Objektorientierte Programmierung (C# und Visual Basic)“.

Erstellen eines benutzerdefinierten Objekts

Um ein benutzerdefiniertes Objekt in PowerShell zu erstellen, müssen Sie zunächst das Cmdlet „New-Object“ verwenden, um das ursprüngliche Objekt zu erstellen. Mit diesem Cmdlet können Sie .NET- oder COM-Objekte aus einer Reihe von Klassen erstellen. Ein benutzerdefiniertes Objekt ist ein spezieller Typ eines .NET-Objekts, das entweder auf der .NET-Klasse Object oder PSObject basiert. Bei der Erstellung des ursprünglichen Objekts gibt es keinen Unterschied zwischen den beiden. Im Allgemeinen wird jedoch die PSObject-Klasse bevorzugt, da beim Hinzufügen von Eigenschaften zu einem Objekt, das auf der Object-Klasse basiert, Probleme auftreten können. Verwenden wir also PSObject.

Um ein Objekt zu erstellen, das auf der PSObject-Klasse basiert, müssen Sie das Cmdlet „New-Object“ mit dem -TypeName-Parameter verwenden und die PSObject-Klasse als Wert des Parameters angeben, etwa so:

$system = New-Object -TypeName PSObject

Wenn Sie diesen Befehl ausführen, wird ein PSCustomObject-Objekt generiert und der Variablen „$system“ zugewiesen. In den meisten Fällen ist es sinnvoll, das Objekt einer Variablen zuzuweisen, damit Sie problemlos mit den Mitgliedern des Objekts arbeiten können. Die Mitglieder sind die Komponenten, aus denen ein Objekt besteht, z. B. Eigenschaften, Methoden, Aliaseigenschaften und Mitgliedersätze.

Bei der Arbeit mit Objekten in PowerShell werden Sie wahrscheinlich zwei Arten von Mitgliedern verwenden: Eigenschaften und Methoden. Eine Eigenschaft beschreibt einen bestimmten Aspekt des Objekts. Eines der Elemente der .NET-Klasse FileInfo ist beispielsweise die Length-Eigenschaft, die die Größe einer Datei in Bytes angibt. Wenn Sie ein FileInfo-Objekt auf der Grundlage dieser Klasse erstellen, können Sie die Eigenschaft Length verwenden, um auf die Größe der mit diesem Objekt verknüpften Datei zuzugreifen. Eine Methode führt eine Aktion in Bezug auf das Objekt aus. Die Klasse FileInfo enthält beispielsweise auch die Methode Delete, mit der Sie die durch das Objekt repräsentierte Datei löschen können.

Die Mitglieder eines Objekts leicht identifizieren zu können, erleichtert die Arbeit mit diesem Objekt. Um eine Liste der Mitglieder eines Objekts abzurufen, können Sie das Cmdlet „Get-Member“ verwenden. Um beispielsweise die Mitglieder des neuen Objekts anzuzeigen, das der Variablen „$system“ zugewiesen wurde, können Sie die Variable „$system“ über die Pipeline an das Cmdlet „Get-Member“ übergeben:

$system | Get-Member

Wie in Abbildung 1 zu sehen ist, basiert das von Ihnen erstellte Objekt auf der Klasse „System.Management.Automation.PSCustomObject“, die nur eine kleine Anzahl von Mitgliedern enthält, die alle Methoden sind. Aber deshalb heißt es ja auch benutzerdefiniertes Objekt – Sie können es anpassen, indem Sie Ihre eigenen Mitglieder hinzufügen.

Abbildung 1: Die Mitgliederliste des neuen Objekts

Bevor ich Ihnen zeige, wie man Mitglieder hinzufügt, möchte ich noch hinzufügen, dass die Klasse PSCustomObject wie viele andere .NET-Klassen auch eine Reihe von versteckten Mitgliedern verschiedener Typen enthält, z. B. memberset und codeproperty. Sie können diese Mitglieder anzeigen, indem Sie beim Aufruf des Cmdlets Get-Member den Parameter -Force angeben. Obwohl eine Erörterung der verborgenen Mitglieder hier den Rahmen sprengen würde, könnte es nützlich sein, die verborgenen Mitglieder zu untersuchen, die der Klasse PSCustomObject und anderen .NET-Klassen zur Verfügung stehen, um die Vorteile Ihrer PowerShell-Objekte voll auszuschöpfen.

Hinzufügen von Eigenschaften zu einem benutzerdefinierten Objekt

Ein benutzerdefiniertes Objekt ist nur so nützlich wie die Mitglieder, die dem Objekt zugeordnet sind. Sie können einem benutzerdefinierten Objekt mehrere verschiedene Arten von Elementen hinzufügen. In diesem Beispiel werden Sie die Mitglieder NoteProperty und ScriptMethod hinzufügen. Eine NoteProperty-Eigenschaft ähnelt einer normalen Eigenschaft, und eine ScriptMethod-Eigenschaft ist einer normalen Methode ähnlich. Sie können einem benutzerdefinierten Objekt keine reguläre Eigenschaft oder Methode hinzufügen, weshalb Sie NoteProperty und ScriptMethod verwenden werden. (Informationen zu den unterstützten Elementen in einem benutzerdefinierten Objekt finden Sie im PowerShell TechNet-Thema „Add-Member“.)

Beginnen wir mit dem Hinzufügen einiger NoteProperty-Elemente zum $system-Objekt. Um die Elemente hinzuzufügen, können Sie das Cmdlet „Add-Member“ verwenden, um die Eigenschaftsnamen und -werte zu definieren. Angenommen, Sie möchten Noteneigenschaften hinzufügen, die auf Daten basieren, die über die in PowerShell integrierten WMI-Funktionen (Windows Management Instrumentation) abgerufen werden. (WMI bietet eine Infrastruktur für die Verwaltung von Daten und Vorgängen in Windows-Betriebssystemen.) Das WMI-Objektmodell umfasst zahlreiche Klassen, die eine breite Palette von Verwaltungsvorgängen unterstützen. Die Klasse „Win32_OperatingSystem“ bietet beispielsweise Zugriff auf Informationen wie den Namen des auf einem Computer installierten Betriebssystems und das letzte auf dieses Betriebssystem angewendete Service Pack.

Um ein WMI-Objekt zu erstellen, verwenden Sie das Cmdlet „Get-WmiObject“ und geben die gewünschte Klasse an. Um beispielsweise ein WMI-Objekt „Win32_OperatingSystem“ zu erstellen und es der Variablen „$os“ zuzuweisen, verwenden Sie den folgenden Code:

$os = Get-WmiObject Win32_OperatingSystem

In diesem Fall rufen Sie Systeminformationen vom lokalen Computer ab, aber das Schöne an WMI ist, dass es auch auf entfernte Windows-Computer zugreifen und diese verwalten kann.

Sie können dann die Variable „$os“ verwenden, um auf die von diesem Objekt zurückgegebenen Informationen zuzugreifen. Wenn Sie ein Objekt auf diese Weise einer Variablen zuweisen, werden die Daten zu diesem Zeitpunkt gesperrt. Wenn beispielsweise ein neues Service Pack auf das Betriebssystem angewendet wird, nachdem Sie die Variable $os erstellt haben, wird die Eigenschaft CSDVersion des Objekts die Änderung nicht widerspiegeln, da das Objekt auf der Grundlage der ursprünglichen Daten erstellt wurde.

Nach der Definition der Variablen $os müssen Sie zwei Add-Member-Befehle angeben. Jeder Befehl benötigt vier Parameter:

  • -InputObject. Mit dem Parameter -InputObject geben Sie das Objekt an, das die neuen Noteneigenschaften erhalten soll. In diesem Fall müssen Sie das Objekt $system angeben.
  • -MemberType. Der -MemberType-Parameter gibt den Typ des zu erstellenden Elements an, daher müssen Sie NoteProperty.
  • -Name angeben. Mit dem Parameter -Name geben Sie den Namen des neuen Mitglieds an. In diesem Beispiel nennen wir das erste Element OperatingSystem und das zweite Element ServicePack.
  • -Value. Dieser Parameter gibt den Wert des Elements an. Für die erste Noteigenschaft müssen Sie $os.Caption angeben, um den Namen des Betriebssystems zurückzugeben. Für die zweite Notiz-Eigenschaft müssen Sie $os.CSDVersion angeben, um das letzte auf das Betriebssystem angewendete Service Pack zurückzugeben.

So sehen die beiden Add-Member-Befehle aus:

Add-Member -InputObject $system -MemberType NoteProperty ` -Name OperatingSystem -Value $os.CaptionAdd-Member -InputObject $system -MemberType NoteProperty ` -Name ServicePack -Value $os.CSDVersion

Beachten Sie, dass ich jeden Add-Member-Befehl in zwei Zeilen unterteilt habe. Am Ende jeder ersten Zeile habe ich ein Häkchen (`) eingefügt, damit der PowerShell-Prozessor weiß, dass er in der nächsten Zeile mit dem vollständigen Befehl fortfahren soll.

Nachdem Sie die Add-Member-Befehle ausgeführt haben, können Sie die Variable „$system“ aufrufen, um ihren Inhalt anzuzeigen:

$system

Abbildung 2 zeigt Beispielergebnisse.

Abbildung 2: Inhalt der Variable „$system“

Sie können die Variable „$system“ auch verwenden, um einzelne Mitglieder aufzurufen. Geben Sie einfach den Variablennamen, gefolgt von einem Punkt, und dann den Namen des Mitglieds an. Der folgende Befehl gibt beispielsweise den aktuellen Wert der Eigenschaft „OperatingSystem note“ zurück:

$system.OperatingSystem

Ein Vorteil der Erstellung eines benutzerdefinierten Objekts besteht darin, dass Sie Notiz-Eigenschaften erstellen können, die auf Daten aus verschiedenen Quellen basieren, sowie eine Notiz-Eigenschaft, deren Wert eine bestimmte Zeichenfolge ist. Sehen Sie sich zum Beispiel den Code in Listing 1 an, der dem Objekt $system drei neue Noteneigenschaften hinzufügt.

$mem = Get-WmiObject Win32_PhysicalMemory$disk = Get-WmiObject Win32_DiskDriveAdd-Member -InputObject $system -MemberType NoteProperty ` -Name PhysicalMemory ` -Value (("{0:N2}" -f ($mem.Capacity/1GB)) + ' GB')Add-Member -InputObject $system -MemberType NoteProperty ` -Name DiskSize ` -Value (("{0:N2}" -f ($disk.Size/1GB)) + ' GB')Add-Member -InputObject $system -MemberType NoteProperty ` -Name Owner -Value "janetp"

Die meisten der Elemente in Listing 1 haben Sie bereits im vorherigen Beispiel gesehen. Beachten Sie jedoch, dass der Code eine Instanz der Klasse Win32_PhysicalMemory erstellt, die der Variablen $mem zugewiesen wird, und eine Instanz der Klasse Win32_DiskDrive, die der Variablen $disk zugewiesen wird. Zwei der hinzugefügten Notiz-Eigenschaften verwenden diese neuen WMI-Objekte als Datenquellen.

Der erste Add-Member-Befehl ruft Daten von der Eigenschaft $mem.Capacity ab, die die Speicherkapazität auf dem Zielsystem bereitstellt. In diesem Fall ist der Parameter -Value jedoch etwas komplexer als im vorherigen Beispiel. Zunächst gibt der Befehl „{0:N2}“ an, gefolgt von -f, einer .NET-Konstruktion zur Formatierung der ausgegebenen Zahl. Damit wird im Wesentlichen festgelegt, dass eine Zahl mit zwei Dezimalstellen zurückgegeben werden soll. Auf die Formatierungsanweisungen folgt ein kurzer Ausdruck ($mem.Capacity/1GB), der den Capacity-Wert durch 1GB teilt. Der Capacity-Wert gibt die Größe des Speichers in Bytes an. Mit PowerShell können Sie Bytes ganz einfach in Gigabytes konvertieren, indem Sie durch 1 GB dividieren. Schließlich fügt der Befehl die Zeichenfolge „GB“ (einschließlich des Leerzeichens) in die Ausgabe ein und schließt das Ganze in Klammern ein.

Der zweite Add-Member-Befehl folgt der gleichen Logik, um die Größe der Festplatte des Computers zurückzugeben. Er verwendet die Eigenschaft $disk.Size, um die Größe in Bytes zurückzugeben, und konvertiert sie dann in Gigabytes.

Der dritte Add-Member-Befehl fügt eine Notiz-Eigenschaft namens Owner hinzu und weist ihr den Zeichenfolgenwert janetp zu. In diesem Fall kann „Besitzer“ alles Mögliche bedeuten – den Hauptbenutzer, den letzten Benutzer, den Administrator oder was auch immer Sie der Eigenschaft zuweisen möchten. Ich habe sie hier nur eingefügt, um zu zeigen, dass Sie eine Notiz-Eigenschaft hinzufügen können, deren Wert eine einfache Zeichenkette ist.

Nachdem Sie dem benutzerdefinierten Objekt die drei Mitglieder hinzugefügt haben, können Sie erneut die Variable $system aufrufen. Sie gibt Ergebnisse wie in Abbildung 3 zurück.

Abbildung 3: Mit dem Cmdlet „Add-Member“ hinzugefügte Notiz-Eigenschaften

Sie haben jetzt ein einzelnes Objekt, das Daten enthält, die von drei verschiedenen WMI-Objekten abgeleitet sind. Das Objekt enthält auch die Eigenschaft Owner, die auf einem String-Wert basiert. Sie können diese Notiz-Eigenschaft wie jedes andere Mitglied aufrufen:

$system.Owner

Wie zu erwarten, gibt der Befehl den Wert janetp zurück. Sie können diesen Wert jedoch in einen anderen ändern, indem Sie der Eigenschaft einen neuen Wert zuweisen, z. B. so:

$system.Owner = "rogert"

In diesem Fall wurde der Eigenschaft „Eigentümer“ der Wert „rogert“ zugewiesen. Wenn Sie diese Notiz-Eigenschaft jetzt aufrufen, wird der neue Wert zurückgegeben.

Wie bei vielen der Aufgaben, die Sie in PowerShell durchführen können, gibt es eine Reihe verschiedener Möglichkeiten, einem benutzerdefinierten Objekt ein Mitglied hinzuzufügen. In PowerShell 3.0 können Sie beispielsweise eine Hashtabelle erstellen und den Hash an den Befehl „New-Object“ übergeben. Der Code in Listing 2 erstellt dieselben fünf Noteneigenschaften, verwendet jedoch eine Hash-Tabelle, um die Namen und Werte der Mitglieder zu übergeben.

$info = @{ "OperatingSystem" = $os.Caption; "ServicePack" = $os.CSDVersion; "PhysicalMemory" = (("{0:N2}" -f ($mem.Capacity/1GB)) + ' GB'); "DiskSize" = (("{0:N2}" -f ($disk.Size/1GB)) + ' GB'); "Owner" = 'janetp'}$system = New-Object -TypeName PSObject -Property $info$system

Dieser Code erstellt zunächst eine Hash-Tabelle, die fünf Eigenschaften/Wertpaare definiert, die jeweils den Noteneigenschaften entsprechen. Wie der Code zeigt, müssen Sie die Eigenschafts-/Wertepaare mit Semikolons trennen. Außerdem müssen Sie die fünf Eigenschafts-/Wertepaare in geschweifte Klammern einschließen und der öffnenden Klammer das at-Symbol (@) voranstellen. Schließlich müssen Sie die Hash-Tabelle der Variablen „$info“ zuweisen.

Nach der Definition der Hash-Tabelle erstellt der Code mit dem Cmdlet „New-Object“ ein Objekt auf der Grundlage der Klasse „PSObject“ und weist es der Variablen „$system“ zu. Nur dieses Mal enthält der Befehl den Parameter -Property, der die Variable $info als Wert annimmt.

Schließlich ruft der Code die Variable $system auf, die Ergebnisse wie in Abbildung 4 zurückgibt. Beachten Sie die Reihenfolge, in der die Eigenschaften zu dem Objekt hinzugefügt wurden. Eines der Probleme bei der Verwendung einer Hash-Tabelle zum Hinzufügen von Noteneigenschaften ist, dass Sie die Reihenfolge nicht steuern können. Um die Reihenfolge zu steuern, müssen Sie das Cmdlet „Add-Member“ verwenden, um die einzelnen Elemente hinzuzufügen.

Abbildung 4: Mit der Hashtabelle erstellte Noteneigenschaften

Hinzufügen von Methoden zu einem benutzerdefinierten Objekt

Nachdem Sie nun gesehen haben, wie einfach es ist, Eigenschaften hinzuzufügen, auf ihre Werte zuzugreifen und diese Werte zu ändern, lassen Sie uns zu den Methoden übergehen. Diese werden etwas komplizierter, weil Methoden etwas tun müssen, und Sie müssen dieses Etwas als Teil des Methodenwerts definieren.

Der Code in Listing 3 erstellt beispielsweise eine Methode, die das aktuelle Datum und die aktuelle Uhrzeit abruft und sie sowohl in ihrem ursprünglichen Format als auch als UTC-Werte (Coordinated Universal Time) zurückgibt.

$method ={ $a = Get-Date -Format F; "Local: " + $a; $b = Get-Date; "UTC: " + $b.ToUniversalTime().DateTime}Add-Member -InputObject $system -MemberType ScriptMethod ` -Name GetUTC -Value $method

Um den Code lesbar zu halten, können Sie den Wert der Methode einer Variablen zuweisen (z. B. $method). Dieser Wert enthält die Ausdrücke, die für die Rückgabe der Datums- und Zeitinformationen erforderlich sind. Sie müssen den Wert jedoch als Skriptblock definieren, um ihn an den Befehl „Add-Member“ zu übergeben. Zu diesem Zweck schließen Sie den Inhalt des Werts in geschweifte Klammern ein. PowerShell weist dann den Wert in seiner aktuellen Form der Variablen als ScriptBlock-Objekt zu.

In Listing 3 enthält der Wert der Methode zwei Ausdrücke. Der erste Ausdruck gibt das aktuelle Datum und die aktuelle Uhrzeit zurück, der zweite Ausdruck gibt die UTC-Version zurück. Sie beginnen den ersten Ausdruck, indem Sie das Cmdlet „Get-Date“ verwenden, um das aktuelle Datum und die aktuelle Uhrzeit abzurufen, die Sie der Variablen „$a“ zuweisen. Beachten Sie, dass Sie beim Aufrufen des Cmdlets „Get-Date“ den Parameter -Format zusammen mit dem Wert F einschließen müssen. Dadurch wird PowerShell angewiesen, den Zeitstempel in einem vollständigen Datums- und Zeitformat anzuzeigen, wie z. B. Monday, August 19, 2013 12:28:25 PM. Sie fügen dann die Zeichenfolge „Local: “ (einschließlich des Leerzeichens) zum Variablenwert hinzu, um das aktuelle Datum und die Uhrzeit zusammen mit dieser Bezeichnung zurückzugeben.

Im zweiten Ausdruck beginnen Sie wieder mit dem Cmdlet „Get-Date“, um das aktuelle Datum und die Uhrzeit zurückzugeben, die Sie der Variablen „$b“ zuweisen. Anschließend verwenden Sie die Methode ToUniversalTime der Variablen, um das Datum und die Uhrzeit als UTC-Wert zurückzugeben, und geben dann die DateTime-Eigenschaft an, um das richtige Format zurückzugeben.

Wenn Sie an dieser Stelle die $method-Variable aufrufen würden, würde sie die beiden Ausdrücke als Zeichenfolgen zurückgeben, so wie sie eingegeben wurden. Da Sie den Variablenwert als Skriptblock definiert haben, werden die Befehle nicht verarbeitet, wenn sie der Variablen $method zugewiesen werden. Stattdessen wird die Variable $method als ScriptBlock-Objekt erstellt, was Sie mit der Methode GetType bestätigen können, um den Typ der Variablen zu sehen:

$method.GetType()

Um mit dem Skriptblock zu arbeiten, müssen Sie die Methode als Mitglied des Objekts $system hinzufügen, nachdem Sie die Variable $method definiert haben. Dazu erstellen Sie einen Add-Member-Befehl, der ScriptMethod als Typ, GetUTC als Namen und die Variable $method als Wert angibt.

Nach dem Ausführen des Codes in Listing 3 können Sie die $system-Variable verwenden, um die GetUTC-Methode auf die gleiche Weise aufzurufen wie die Eigenschaften:

$system.GetUTC()

Beachten Sie jedoch, dass Sie beim Aufrufen der Skriptmethode die Klammern einschließen müssen, wie bei jeder anderen Methode, auch wenn Sie keine Argumente übergeben. Die Methode sollte nun Ergebnisse ähnlich denen in Abbildung 5 zurückgeben, jedoch mit dem Datum und der Uhrzeit, zu der Sie die Methode aufgerufen haben.

Abbildung 5: Beispielhafte Ergebnisse der Methode GetUTC()

Im wirklichen Leben werden Sie wahrscheinlich Methoden erstellen wollen, die mehr Aussagekraft haben. Zum Beispiel könnte das $system-Objekt WMI-Verwaltungsaufgaben in seine Skriptmethoden einbeziehen. Wenn Sie dies tun, müssen Sie die Methode vollständig testen, um sicherzustellen, dass Ihre Befehle genau das tun, was sie tun sollen. PowerShell und WMI sind beides leistungsstarke Tools und sollten daher bei der Verwaltung von Windows-Computern mit Vorsicht eingesetzt werden.

Hinzufügen von benutzerdefinierten Objekten zu einem Array

Benutzerdefinierte Objekte sind nicht auf eigenständige Objekte beschränkt, die Sie einmal verwenden und dann wegwerfen. Sie können diese Objekte zu einem Objekt-Array hinzufügen und dann über dieses Array auf die Objekte zugreifen. Nehmen wir zum Beispiel an, Sie möchten Informationen bearbeiten, die Sie von mehreren Computern abrufen. Diese Informationen könnten Details über den Speicher und die logischen Laufwerke enthalten, die auf diesen Systemen verfügbar sind. Sie möchten in der Lage sein, mit diesen Details auf sinnvolle Weise in PowerShell zu arbeiten. Aufgrund des objektorientierten Charakters von PowerShell ist es oft am einfachsten, diese Informationen in Objekte zu packen, um mit diesen Daten zu arbeiten.

Schauen wir uns ein Beispiel an, wie Sie dies tun können. Für diese Diskussion ist der Ansatz, mit dem die Informationen über die verschiedenen Computer gesammelt werden, unwichtig. Sie könnten z. B. eine foreach-Schleife in PowerShell einrichten, die WMI zum Abrufen der Informationen von den verschiedenen Arbeitsstationen verwendet. Unabhängig von der verwendeten Methode nehmen Sie der Kürze halber an, dass Sie die Informationen in einer kommagetrennten Textdatei gesammelt haben, die die in Abbildung 6 gezeigten Daten enthält.

Abbildung 6: Gesammelte WMI-Daten

Die Textdatei enthält eine Kopfzeile und eine Zeile für die logischen Laufwerke der einzelnen Systeme. Die erste Datenzeile enthält beispielsweise Details über das logische Laufwerk C auf dem Computer ws01. Das logische Laufwerk hat eine Kapazität von 500 GB, davon sind 225 GB frei. Das System verfügt außerdem über 4 GB Arbeitsspeicher. Die zweite Zeile zeigt an, dass derselbe Computer auch das logische Laufwerk D enthält, das dieselbe Kapazität wie das Laufwerk C hat, aber 320 GB freien Speicherplatz aufweist.

Das Ziel ist es, jede Datenzeile in ein eigenes benutzerdefiniertes Objekt zu verwandeln und diese Objekte dann zu einem Array hinzuzufügen. Sie können dann auf die Objekte innerhalb des Arrays zugreifen, indem Sie die Daten über die Pipeline an andere PowerShell-Befehle weiterleiten. Der Code in Listing 4 definiert ein leeres Array, importiert die Daten aus der Textdatei und verwendet dann eine foreach-Schleife, um die Objekte zu erstellen und dem Array hinzuzufügen.

$SystemInfo = @()$SourceData = Import-CSV C:\DataFiles\SourceData.txtforeach ($source in $SourceData){ $system = New-Object -TypeName PSObject $system | Add-Member -Type NoteProperty ` -Name Computer -Value $source.Computer $system | Add-Member -Type NoteProperty ` -Name DeviceID -Value $source.DeviceID $system | Add-Member -Type NoteProperty ` -Name DriveSize -Value ($source.DriveSize) $system | Add-Member -Type NoteProperty ` -Name UsedSpace ` -Value ($source.DriveSize - $Source.FreeSpace) $system | Add-Member -Type NoteProperty ` -Name FreeSpace -Value ($source.FreeSpace) $SystemInfo += $system}

Wie Sie sehen, wird im ersten Schritt das leere Array (@()) erstellt und der Variablen „$SystemInfo“ zugewiesen. Schließlich fügen Sie diesem Array die benutzerdefinierten Objekte hinzu.

Als Nächstes verwenden Sie das Cmdlet „Import-CSV“, um die Daten in die Variable „$SourceData“ zu importieren. Für diese Übung wird die Textdatei „SourceData.txt“ genannt und im Ordner „C:\DataFiles“ gespeichert. Das Cmdlet „Import-CSV“ ruft jede Zeile als eigenes Objekt ab und speichert sie in „$SourceData“. Zu diesem Zeitpunkt könnten Sie diese Variable verwenden, um auf die Daten zuzugreifen, aber Sie hätten keine Kontrolle über die im Objekt enthaltenen Elemente und könnten auch keine Elemente hinzufügen.

Der nächste Schritt besteht also darin, eine foreach-Schleife zu erstellen, mit der Sie ein benutzerdefiniertes Objekt für jede Zeile in der Textdatei erstellen können. Die foreach-Bedingung ($source in $SourceData) gibt an, dass jede Zeile in $SourceData der Variablen $source zugewiesen werden soll, während der Code durch die foreach-Schleife iteriert. Die im foreach-Skriptblock definierte Logik (in geschweiften Klammern) wird dann für jede Zeile einmal ausgeführt, wobei bei jeder Iteration ein anderes $source-Objekt verwendet wird. (Weitere Informationen zum Erstellen einer foreach-Schleife finden Sie im PowerShell TechNet-Thema about_ForEach.)

Werfen wir einen genaueren Blick auf den foreach-Skriptblock. Der erste Befehl erstellt das anfängliche Objekt und speichert es in der Variablen „$system“, wie Sie in den vorherigen Beispielen gesehen haben. Anschließend wird die Variable $system an einen Add-Member-Befehl weitergeleitet, um die erste Noteneigenschaft zu erstellen. Dies ist ein etwas anderes Format als zuvor. Anstatt den Parameter -InputObject in den Add-Member-Befehl aufzunehmen, wird einfach $system über die Pipeline an den Befehl übergeben. Dies führt zu denselben Ergebnissen wie in den früheren Beispielen für Add-Member-Befehle. Ich habe diesen Ansatz hier nur gewählt, um eine weitere Möglichkeit zu demonstrieren, wie Sie mit PowerShell Mitglieder hinzufügen können.

Für den Wert des Add-Member-Befehls verwenden Sie die $source-Variable, um die Eigenschaft Computer aufzurufen, die dem Feld Computer in den Quelldaten entspricht. Der zweite Add-Member-Befehl funktioniert auf dieselbe Weise, mit dem Unterschied, dass er Daten aus der Eigenschaft DeviceID abruft. Beachten Sie, dass die Eigenschaft Memory nicht enthalten ist. Wenn Sie ein benutzerdefiniertes Objekt erstellen, können Sie bestimmte Eigenschaften auslassen oder sie in einer anderen Reihenfolge anordnen.

Der dritte Add-Member-Befehl funktioniert ähnlich wie die ersten beiden, mit dem Unterschied, dass er auf die Eigenschaft DriveSize zugreift. Da Sie mit diesen Daten möglicherweise als numerischen Wert und nicht als Zeichenfolge arbeiten möchten, konvertiert der Befehl die Daten ausdrücklich in eine Zahl. Dies wird erreicht, indem dem Eigenschaftsnamen ein vorangestellt wird, um anzuzeigen, dass Sie den Datentypint verwenden möchten, und dann der gesamte Eigenschaftsausdruck in Klammern eingeschlossen wird.

Der vierte Befehl Add-Member hat eine etwas andere Funktion. Er erstellt ein berechnetes Element, das den Wert FreeSpace vom Wert DriveSize subtrahiert, um die Menge des belegten Speicherplatzes zu ermitteln. Auch hier wird dem Eigenschaftsnamen ein vorangestellt, und der gesamte Ausdruck wird in Klammern gesetzt. Die Möglichkeit, eine berechnete Eigenschaft zu erstellen, ist einer der Hauptgründe, warum man benutzerdefinierte Objekte erstellen möchte.

Der letzte Add-Member-Befehl funktioniert genauso wie der dritte, nur dass er Daten aus der FreeSpace-Eigenschaft abruft.

Der letzte Befehl im foreach-Skriptblock fügt das aktuelle $system-Objekt zum Array $SystemInfo hinzu. Beachten Sie, dass der Operator += verwendet wird, um sicherzustellen, dass das neue $system-Objekt bei jeder Iteration der Schleife hinzugefügt wird, ohne dass etwas überschrieben wird.

Nachdem Sie den Code in Listing 4 ausgeführt haben, können Sie die Variable aufrufen, um ihren Inhalt anzuzeigen. Abbildung 7 zeigt eine Teilliste der Daten, die jetzt im Array $SystemInfo gespeichert sind.

Abbildung 7: Im Array $SystemInfo gespeicherte Daten

Speziell zeigt sie die Daten für die ersten sieben Objekte im Array, was den ersten sieben Datenzeilen in der ursprünglichen Textdatei entspricht. Jede Gruppierung steht für eines der Objekte, die dem Array $SystemInfo hinzugefügt wurden. Sie können überprüfen, ob Sie ein Objektarray erstellt haben, indem Sie mit der GetType-Methode den Typ der Variablen abrufen:

$SystemInfo.GetType()

Wenn dieser Befehl einen BaseType von System.Array zurückgibt, ist die Variable $SystemInfo tatsächlich ein Objektarray, das benutzerdefinierte Objekte aufnehmen kann. Sie können diese Variable dann verwenden, um die Daten nach eigenem Ermessen zu manipulieren. Sie können die Variable beispielsweise über die Pipeline an einen Sort-Object-Befehl übergeben, um die Daten auf der Grundlage der FreeSpace-Werte in absteigender Reihenfolge zu sortieren:

$SystemInfo | Sort FreeSpace -Descending

In diesem Fall verwendet der Befehl den Sort-Alias, um auf das Cmdlet „Sort-Object“ zu verweisen, und enthält die FreeSpace-Eigenschaft und den -Descending-Parameter. Wie in Abbildung 8 zu sehen ist, werden die Objekte nun nach den FreeSpace-Werten aufgelistet, wobei der größte freie Speicherplatz zuerst aufgeführt wird. Auch hier handelt es sich nur um eine Teilliste.

Abbildung 8: Daten sortiert nach freiem Speicherplatz

Sie können die Daten auch nach mehreren Spalten sortieren. Sie können die Daten beispielsweise zuerst nach der Eigenschaft „Computer“ und dann nach der Eigenschaft „Freier Speicherplatz“ in absteigender Reihenfolge sortieren:

$SystemInfo | Sort Computer, FreeSpace -Descending

Wie zu erwarten, sehen die Ergebnisse jetzt ganz anders aus, wie Abbildung 9 zeigt.

Abbildung 9: Nach dem Computernamen und der Menge an freiem Speicherplatz sortierte Daten in absteigender Reihenfolge

Eine der Folgen dieser Sortierung der Spalten ist, dass sowohl die Computerwerte als auch die FreeSpace-Werte in absteigender Reihenfolge sortiert sind. Mit dem Cmdlet „Sort-Object“ können Sie nicht einfach eine Spalte in aufsteigender Reihenfolge und eine andere in absteigender Reihenfolge sortieren. Wenn Sie den Parameter -Descending angeben, werden alle Daten in dieser Reihenfolge sortiert. Sie können diese Einschränkung jedoch umgehen, indem Sie Ausdrücke für jede Eigenschaft erstellen, die angeben, wie diese Werte sortiert werden sollen. Der folgende Befehl sortiert beispielsweise zuerst nach der Eigenschaft „Computer“ in aufsteigender Reihenfolge und dann nach der Eigenschaft „FreeSpace“ in absteigender Reihenfolge:

$SystemInfo | Sort ` @{Expression="Computer"; Descending=$false}, @{Expression="FreeSpace"; Descending=$true}

Der erste Sort-Object-Ausdruck setzt die Eigenschaft „Expression“ auf „Computer“ und die Eigenschaft „Absteigend“ auf „$false“. Der zweite Ausdruck setzt die Eigenschaft „Expression“ auf „FreeSpace“ und die Eigenschaft „Descending“ auf „$true“. (Die Variablen „$true“ und „$false“ sind eingebaute Systemvariablen, die die booleschen Werte „true“ (wahr) und „false“ (falsch) von 1 bzw. 0 liefern.) Anschließend müssen Sie jeden Ausdruck in geschweifte Klammern einschließen und jeder öffnenden Klammer das Symbol at (@) voranstellen. Nun werden die Daten in der gewünschten Reihenfolge sortiert, wie in Abbildung 10 zu sehen ist.

Abbildung 10: Daten sortiert nach dem Computernamen in aufsteigender Reihenfolge und der Menge an freiem Speicherplatz in absteigender Reihenfolge

Das mag wie ein Overkill zum Thema Sortieren erscheinen, aber es zeigt die Flexibilität der Arbeit mit Objekten in einem Array. Und Sie sind sicherlich nicht auf das Cmdlet „Sort-Object“ beschränkt. Im folgenden Befehl wird beispielsweise die Variable „$SystemInfo“ über die Pipeline an das Cmdlet „Where-Object“ übergeben:

$SystemInfo | Where DriveSize -gt 250 | Sort FreeSpace -Descending

In diesem Fall verwendet der Befehl den Where-Alias, um auf das Cmdlet „Where-Object“ zu verweisen. Außerdem wird angegeben, dass der DriveSize-Wert größer als 250 sein muss, um in die Ergebnisse aufgenommen zu werden. (In PowerShell wird -gt für den Größer-als-Operator verwendet.) Die Ergebnisse, die diese Kriterien erfüllen, werden über die Pipeline an das Cmdlet „Sort-Object“ übergeben, damit die Daten in der richtigen Reihenfolge angezeigt werden.

Sie können die sortierten Daten sogar über die Pipeline an einen Select-Object-Befehl übergeben, z. B. so:

$SystemInfo | Where DriveSize -gt 250 | Sort FreeSpace -Descending | Select -First 5

In diesem Befehl werden mit dem Cmdlet „Select-Object“ (auf das über den Select-Alias verwiesen wird) nur die ersten fünf Zeilen der Ergebnismenge zurückgegeben. Wie Sie sehen, stehen Ihnen nach dem Hinzufügen von benutzerdefinierten Objekten zum Array „$SystemInfo“ verschiedene Optionen für die Arbeit mit diesen Objekten zur Verfügung.

Benutzerdefinierte Objekte optimal nutzen

Bei der Erstellung von benutzerdefinierten Objekten in PowerShell handelt es sich in den meisten Fällen um einen recht einfachen Prozess. Die Komplexität ergibt sich in der Regel aus den Wertausdrücken, die Sie für Ihre Notiz-Eigenschaften oder Skriptmethoden definieren. Die Ausdrücke in diesen Beispielen sind relativ einfach im Vergleich zu den Arten von Ausdrücken, die Sie in PowerShell erstellen können. Dennoch sollte das, was Sie hier gesehen haben, Ihnen die Grundlage für die Erstellung benutzerdefinierter Objekte bieten. Wenn sie effektiv verwendet werden, können sie eine leistungsstarke Komponente Ihrer PowerShell-Skripts sein, unabhängig davon, ob Sie einzelne Objekte erstellen, sie einem Array hinzufügen oder sie auf andere Weise verwenden. Sie können z. B. benutzerdefinierte Objekte in Ihrem PowerShell-Profil erstellen, damit sie bei jedem Start einer neuen Sitzung verfügbar sind. Wie Sie benutzerdefinierte Objekte in Ihren Skripts verwenden, bleibt Ihnen überlassen. Sie sollten nur wissen, dass das benutzerdefinierte Objekt ein effektives, flexibles Tool ist, das viele Ihrer Skriptanforderungen erfüllen kann.

Weitere Informationen zum Erstellen von benutzerdefinierten Objekten in Windows PowerShell finden Sie in Bill Stewarts „Creating Custom Objects in Windows PowerShell“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.