Die textuelle Ausgabe von Befehlen im PowerShell-Interpreter ist lediglich eine Möglichkeit, Informationen in einer für den Menschen verständlichen Form darzustellen. Tatsächlich basiert die Umgebung auf der Arbeit mit Objekten: Cmdlets und Funktionen erhalten sie als Eingabe und , und die in der interaktiven Sitzung und in Skripten verfügbaren Variablentypen basieren auf .NET-Klassen. Im vierten Artikel der Reihe werden wir die Arbeit mit Objekten genauer untersuchen.
Inhaltsverzeichnis:
Objekte in PowerShell
Erinnern wir uns, dass ein Objekt eine Ansammlung von Datenfeldern (Eigenschaften, Ereignisse usw.) und Methoden zu deren Verarbeitung ist. Seine Struktur wird durch den Typ definiert, der in der Regel auf den in der einheitlichen .NET Core-Plattform verwendeten Klassen basiert. Außerdem gibt es die Möglichkeit, mit COM-, CIM (WMI)- und ADSI-Objekten zu arbeiten. Eigenschaften und Methoden sind notwendig, um verschiedene Aktionen mit Daten auszuführen; zudem können in PowerShell Objekte als Argumente an Funktionen und Cmdlets übergeben und ihre Werte Variablen zugewiesen werden. Es gibt auch (Pipelines). Jeder Befehl in der Pipeline überträgt seine Ausgabe nacheinander — Objekt für Objekt. Für die Verarbeitung können kompiliierte Cmdlets verwendet oder eigene , um verschiedene Manipulationen mit Objekten in der Pipeline durchzuführen: Filtern, Sortieren, Gruppieren und sogar Ändern ihrer Struktur. Die Datenübertragung in dieser Form hat einen erheblichen Vorteil: Der empfangende Befehl muss sich nicht mit der syntaktischen Analyse eines Byte-Stroms (Textes) befassen, alle benötigten Informationen lassen sich leicht durch den Zugriff auf die entsprechenden Eigenschaften und Methoden extrahieren.
Struktur von Objekten anzeigen
Zum Beispiel führen wir das Cmdlet Get-Process aus, das Informationen über laufende Prozesse im System bereitstellt:

Es wird einige formatierte Textdaten auf dem Bildschirm ausgeben, die keine Vorstellung von den Eigenschaften der zurückgegebenen Objekte und deren Methoden vermitteln. Um die Ausgabe detailliert zu analysieren, müssen wir lernen, die Struktur von Objekten zu erkunden, und dabei hilft uns das Cmdlet Get-Member:
Get-Process | Get-Member 
Hier sehen wir bereits den Typ und die Struktur, und mit Hilfe zusätzlicher Parameter können wir zum Beispiel nur die Eigenschaften des eingegebenen Objekts ausgeben:
Get-Process | Get-Member -MemberType PropertyDieses Wissen wird benötigt, um Verwaltungsaufgaben im interaktiven Modus zu lösen oder um eigene Skripte zu schreiben: zum Beispiel, um Informationen über hängende Prozesse anhand der Eigenschaft Responding zu erhalten.
Objekte filtern
PowerShell ermöglicht es, Objekte, die eine bestimmte Bedingung erfüllen, durch die Pipeline zu leiten:
Where-Object { Skriptblock }Das Ergebnis der Ausführung des Skriptblocks in geschweiften Klammern muss ein logischer Wert sein. Wenn er wahr ist ($true), wird das eingegebene Objekt an das Cmdlet Where-Object weitergegeben, andernfalls (Wert $false) wird es entfernt. Zum Beispiel geben wir eine Liste der gestoppten Windows Server-Dienste aus, d.h. derjenigen, bei denen die Eigenschaft Status den Wert „Stopped“ hat:
Get-Service | Where-Object {$_.Status -eq "Stopped"} 
Hier sehen wir wieder eine textuelle Darstellung, aber wenn man will, ist es nicht schwer, den Typ und das innere Bild der Objekte, die durch die Pipeline laufen, zu verstehen:
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member 
Objekte sortieren
Bei der Verarbeitung von Objekten durch die Pipeline tritt häufig die Notwendigkeit auf, diese zu sortieren. Dem Cmdlet Sort-Object werden die Namen der Eigenschaften (Sortierschlüssel) übergeben, und es gibt die Objekte zurück, die nach ihren Werten geordnet sind. Die ausgegebenen laufenden Prozesse lassen sich leicht nach der verbrauchten CPU-Zeit (Eigenschaft cpu) sortieren:
Get-Process | Sort-Object –Property cpuDer Parameter -Property muss beim Aufruf des Cmdlets Sort-Object nicht angegeben werden — er wird standardmäßig verwendet. Für eine absteigende Sortierung wird der Parameter -Descending verwendet:
Get-Process | Sort-Object cpu -Descending 
Objekte und deren Teile herausfiltern
Das Cmdlet Select-Object ermöglicht es, eine bestimmte Anzahl von Objekten am Anfang oder Ende der Pipeline mit den Parametern -First oder -Last auszuwählen. Damit können einzelne Objekte oder bestimmte Eigenschaften ausgewählt und darauf basierend neue Objekte erstellt werden. Lassen Sie uns die Funktionsweise des Cmdlets anhand einfacher Beispiele erläutern.
Der folgende Befehl gibt Informationen über 10 Prozesse aus, die den höchsten Speicherverbrauch aufweisen (Eigenschaft WS):
Get-Process | Sort-Object WS -Descending | Select-Object -First 10 
Es ist möglich, nur bestimmte Eigenschaften der durch die Pipeline laufenden Objekte auszuwählen und darauf basierend neue zu erstellen:
Get-Process | Select-Object ProcessName, Id -First 1Durch die Arbeit der Pipeline erhalten wir ein neues Objekt, dessen Struktur sich von der des durch das Cmdlet Get-Process zurückgegebenen Objekts unterscheidet. Lassen Sie uns dies mit Get-Member überprüfen:
Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member 
Bitte beachten Sie, dass Select-Object ein einzelnes Objekt (-First 1) zurückgibt, das nur zwei von uns angegebene Felder hat: deren Werte wurden aus dem ersten an die Pipeline übergebenen Objekt des Cmdlets Get-Process kopiert. Die Verwendung von Select-Object ist eine Methode zur Erstellung von Objekten in PowerShell-Skripten:
$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType() 
Mit Select-Object können berechnete Eigenschaften zu Objekten hinzugefügt werden, die in Form von dargestellt werden. Dabei entspricht der Wert seines ersten Schlüssels dem Namen der Eigenschaft, und der Wert des zweiten Schlüssels ist der Wert der Eigenschaft für das aktuelle Element der Pipeline:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} 
Lassen Sie uns die Struktur der durch die Pipeline laufenden Objekte betrachten:
Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member 
ForEach-Object, Group-Object und Measure-Object
Für die Arbeit mit Objekten gibt es auch andere Cmdlets. Zum Beispiel werden wir über drei der nützlichsten sprechen:
ForEach-Object erlaubt es, Code in PowerShell für jedes Objekt in der Pipeline auszuführen:
ForEach-Object { Skriptblock }Group-Object gruppiert Objekte nach dem Wert einer Eigenschaft:
Group-Object PropertyNameWenn man es mit dem Parameter -NoElement ausführt, kann man die Anzahl der Elemente in den Gruppen ermitteln.
Measure-Object aggregiert verschiedene Zusammenfassungsparameter basierend auf den Werten der Felder der Objekte in der Pipeline (berechnet die Summe und findet die Minimal-, Maximal- oder Durchschnittswerte):
Measure-Object -Property PropertyName -Minimum -Maximum -Average -SumIn der Regel werden die betrachteten Cmdlets interaktiv verwendet, während in Skripten häufiger BLocks Begin, Process und End erstellt werden.
Erstellen von .NET- und COM-Objekten (New-Object)
Es gibt viele Softwarekomponenten mit .NET Core- und COM-Interfaces, die für Systemadministratoren nützlich sind. Mit der Klasse System.Diagnostics.EventLog kann man Systemprotokolle direkt aus Windows PowerShell verwalten. Lassen Sie uns ein Beispiel für die Erstellung einer Instanz dieser Klasse mit dem Cmdlet New-Object und dem Parameter -TypeName betrachten:
New-Object -TypeName System.Diagnostics.EventLog 
Da wir kein bestimmtes Ereignisprotokoll angegeben haben, enthält die erhaltene Objektinstanz keine Daten. Um dies zu ändern, muss beim Erstellen des Objekts eine spezielle Konstruktormethode mit dem Parameter -ArgumentList aufgerufen werden. Wenn wir auf das Anwendungsprotokoll zugreifen möchten, sollte der Konstruktor die Zeichenfolge „Application“ als Argument übergeben bekommen.
$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog 
Bitte beachten Sie: Die Ausgaben des Befehls haben wir in der Variablen $AppLog gespeichert. Obwohl in der interaktiven Nutzung normalerweise Pipelines verwendet werden, erfordert das Schreiben von Skripten oft die Speicherung eines Verweises auf das Objekt. Darüber hinaus befinden sich die grundlegenden .NET Core-Klassen im Namensraum System: PowerShell sucht standardmäßig darin nach den angegebenen Typen, weshalb die Verwendung von Diagnostics.EventLog anstelle von System.Diagnostics.EventLog durchaus korrekt ist.
Um mit dem Protokoll zu arbeiten, können die entsprechenden Methoden angesprochen werden:
$AppLog | Get-Member -MemberType Method 
Nehmen wir an, es wird mit der Methode Clear() bereinigt, wenn die Berechtigungen vorhanden sind:
$AppLog.Clear()Das Cmdlet New-Object wird auch für die Arbeit mit COM-Komponenten verwendet. Davon gibt es viele - von den mit dem Server gelieferten Windows-Skripten bis hin zu ActiveX-Anwendungen, wie zum Beispiel Internet Explorer. Um ein COM-Objekt zu erstellen, muss der Parameter -ComObject mit der Programm-ID ProgId der gewünschten Klasse angegeben werden:
New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObjectUm eigene Objekte mit einer beliebigen Struktur zu erstellen, erscheint die Verwendung von New-Object zu veraltet und umständlich; dieses Cmdlet wird für die Arbeit mit externen Programmierschnittstellen zu PowerShell verwendet. In den nächsten Artikeln wird dieses Thema ausführlicher behandelt. Neben .NET- und COM-Objekten werden wir auch CIM- (WMI) und ADSI-Objekte untersuchen.
Aufruf statischer Methoden
Instanzen bestimmter .NET Core-Klassen können nicht erstellt werden: zu ihnen gehören System.Environment und System.Math. Sie sind und enthalten nur statische Eigenschaften und Methoden. Im Grunde nehmen sie die Rolle von Nachschlagebibliotheken ein, die ohne die Erstellung von Objekten genutzt werden. Auf eine statische Klasse kann über einen Literalin der Typbezeichnung in eckige Klammern verwiesen werden. Wenn man sich jedoch die Struktur des Objekts mit Get-Member ansieht, erkennt man den Typ System.RuntimeType anstelle von System.Environment:
[System.Environment] | Get-Member 
Um nur statische Elemente anzuzeigen, müssen Sie Get-Member mit dem Parameter -Static aufrufen (beachten Sie den Objekttyp):
[System.Environment] | Get-Member -Static 
Für den Zugriff auf statische Eigenschaften und Methoden werden zwei aufeinanderfolgende Doppelpunkte anstelle eines Punktes nach dem Literal verwendet:
[System.Environment]::OSVersionOder
$test=[System.Math]::Sqrt(25)
$test
$test.GetType() 
Typ PSCustomObject
Unter den vielen in PowerShell verfügbaren Datentypen ist PSCustomObject besonders erwähnenswert, da es dazu dient, Objekte mit beliebiger Struktur zu speichern. Die Erstellung eines solchen Objekts mit dem Cmdlet New-Object gilt als klassisch, aber umständlich und veraltet:
$object = New-Object –TypeName PSCustomObject -Property @{Name = 'Ivan Danko';
City = 'Moskau';
Country = 'Russland'}
Betrachten wir die Struktur des Objekts:
$object | Get-Member 
Seit PowerShell 3.0 ist auch eine andere Syntax verfügbar:
$object = [PSCustomObject]@{Name = 'Ivan Danko';
City = 'Moskau';
Country = 'Russland'
}
Auf die Daten kann auf eine der gleichwertigen Weisen zugegriffen werden:
$object.Name
$object.'Name'
$value = 'Name'
$object.$value
Lassen Sie uns ein Beispiel für die Umwandlung in ein Objekt einer bestehenden Hashtable anführen:
$hash = @{'Name'='Ivan Danko'; 'City'='Moskau'; 'Country'='Russland'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()

Ein Nachteil dieses Objekttyps ist, dass die Reihenfolge seiner Eigenschaften sich ändern kann. Um dies zu vermeiden, sollte das Attribut [ordered] verwendet werden:
$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko';
City = 'Moskau';
Country = 'Russland'
}
Es gibt auch andere Möglichkeiten, ein Objekt zu erstellen: oben haben wir die Verwendung des Cmdlets . Jetzt bleibt nur noch zu klären, wie Elemente hinzugefügt und entfernt werden. Dies für das Objekt aus dem vorherigen Beispiel zu tun, ist recht einfach:
$object | Add-Member –MemberType NoteProperty –Name Age –Value 33
$object | Get-Member

Das Cmdlet Add-Member ermöglicht es, dem zuvor erstellten Objekt $object neben Eigenschaften auch Methoden durch die Verwendung der Konstruktion "-MemberType ScriptMethod" hinzuzufügen:
$ScriptBlock = {
# Code
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member
Beachten Sie: Zur Speicherung des Codes der neuen Methode haben wir die Variable $ScriptBlock vom Typ ScriptBlock verwendet.

Zum Entfernen von Eigenschaften wird die entsprechende Methode verwendet:
$object.psobject.properties.remove('Name')
Eigene Klassen erstellen
In PowerShell 5.0 wurde die Möglichkeit zur Definition unter Verwendung der für objektorientierte Programmiersprachen typischen Syntax. Dafür ist das Schlüssewort Class vorgesehen, gefolgt von der Angabe des Klassennamens und der Beschreibung ihres Körpers in geschweiften Klammern:
class MyClass
{
# Körper der Klasse
}
Dies ist ein echter Typ von .NET Core, dessen Eigenschaften, Methoden und andere Elemente in seinem Körper beschrieben werden. Betrachten wir ein Beispiel zur Definition einer einfachsten Klasse:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
}
Um ein Objekt (eine Instanz der Klasse) zu erstellen, wird das Cmdlet , oder der Literaltyp [MyClass] und new (Standardkonstruktor):
$object = New-Object -TypeName MyClassoder
$object = [MyClass]::new()Analysieren wir die Struktur des Objekts:
$object | Get-Member 
Man sollte die Sichtbarkeit nicht vergessen: Es ist nicht möglich, auf den Typnamen als Zeichenfolge zuzugreifen oder den Literaltyp außerhalb des Skripts oder Moduls zu verwenden, in dem die Klasse definiert ist. Dabei können Funktionen Instanzen der Klasse (Objekte) zurückgeben, die außerhalb des Moduls oder Skripts verfügbar sind.
Nach der Erstellung des Objekts fügen wir die Eigenschaften hinzu:
$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object

Es ist zu beachten, dass in der Klassendefinition nicht nur die Typen der Eigenschaften festgelegt werden, sondern auch deren Standardwerte:
class Example
{
[string]$Name = 'John Doe'
}
Die Beschreibung einer Klassenmethode ähnelt der Beschreibung einer Funktion, jedoch ohne Verwendung des Schlüsselworts function. Wie in der Funktion können Parameter an Methoden übergeben werden, falls erforderlich:
class MyClass
{
[string]$Name
[string]$City
[string]$Country
# Beschreibung der Methode
Smile([bool]$param1)
{
If($param1) {
Write-Host ':)'
}
}
}
Jetzt kann unser Klassenschein lächeln:
$object = [MyClass]::new()
$object.Smile($true)
Methoden können überladen werden, außerdem hat die Klasse , sowie Konstruktoren, deren Namen mit dem Namen der Klasse übereinstimmen. Eine in einem PowerShell-Skript oder -Modul definierte Klasse kann als Basisklasse für eine andere dienen – so wird die Vererbung realisiert. Dabei können existierende .NET-Klassen als Basisklassen verwendet werden:
class MyClass2 : MyClass
{
# Körper der neuen Klasse, deren Basisklasse MyClass ist
}
[MyClass2]::new().Smile($true)
Unsere Beschreibung der Arbeit mit Objekten in PowerShell ist schwer als umfassend zu bezeichnen. In den kommenden Veröffentlichungen werden wir versuchen, sie anhand praktischer Beispiele zu vertiefen: Der fünfte Artikel der Reihe wird sich mit Fragen der Integration von PowerShell mit externen Softwarekomponenten befassen. Frühere Teile finden Sie über die untenstehenden Links.
Quelle: habr.com
