- 10/05/2020
- 8 Minuten zu lesen
-
- j
- m
- s
- j
- c
PSCustomObject
sind ein großartiges Werkzeug, das Sie in Ihren PowerShell-Werkzeuggürtel aufnehmen können. Beginnen wir mit den Grundlagen und arbeiten uns dann zu den fortgeschrittenen Funktionen vor. Die Idee hinter der Verwendung von PSCustomObject
ist es, eine einfache Möglichkeit zur Erstellung strukturierter Daten zu haben. Schauen Sie sich das erste Beispiel an, damit Sie eine bessere Vorstellung davon bekommen, was das bedeutet.
Note
Die ursprüngliche Version dieses Artikels erschien im Blog von @KevinMarquette. DasPowerShell-Team dankt Kevin dafür, dass er diesen Inhalt mit uns geteilt hat. Bitte besuchen Sie seinen Blog unterPowerShellExplained.com.
- Erstellen eines PSCustomObject
- Konvertieren einer Hashtabelle
- Legacy-Ansatz
- Speichern in einer Datei
- Arbeiten mit Eigenschaften
- Hinzufügen von Eigenschaften
- Eigenschaften entfernen
- Eigenschaftsnamen aufzählen
- Dynamischer Zugriff auf Eigenschaften
- Konvertieren Sie PSCustomObject in eine Hashtabelle
- Prüfen auf Eigenschaften
- Hinzufügen von Objektmethoden
- Objekte vs. Werttypen
- psobject.copy()
- PSTypeName für benutzerdefinierte Objekttypen
- Verwenden von DefaultPropertySet (der lange Weg)
- Update-TypeData mit DefaultPropertySet
- Update-TypeData mit ScriptProperty
- Funktionsparameter
- Funktion OutputType
- Abschließende Gedanken
Erstellen eines PSCustomObject
Ich liebe die Verwendung von in PowerShell. Aus diesem Grund überspringe ich alle anderen Möglichkeiten, ein Objekt zu erstellen, aber ich muss erwähnen, dass die meisten dieser Beispiele PowerShell v3.0 und neuer sind.
$myObject = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Diese Methode funktioniert gut für mich, weil ich Hash-Tabellen für fast alles verwende. Aber es gibt Momente, in denen ich möchte, dass PowerShell Hash-Tabellen eher wie ein Objekt behandelt. Der erste Punkt, an dem Sie den Unterschied bemerken, ist, wenn Sie Format-Table
oder Export-CSV
verwenden möchten und feststellen, dass eine Hashtabelle nur eine Sammlung von Schlüssel/Wert-Paaren ist.
Sie können dann auf die Werte wie auf ein normales Objekt zugreifen und sie verwenden.
$myObject.Name
Konvertieren einer Hashtabelle
Wenn ich schon beim Thema bin, wussten Sie, dass man das so machen kann:
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = $myHashtable
Ich bevorzuge es, das Objekt von Anfang an zu erstellen, aber es gibt Zeiten, in denen man zuerst mit einer Hashtabelle arbeiten muss. Dieses Beispiel funktioniert, weil der Konstruktor eine Hashtabelle für die Objekteigenschaften nimmt. Ein wichtiger Hinweis ist, dass diese Methode zwar funktioniert, aber keine exakte Entsprechung ist. Der größte Unterschied besteht darin, dass die Reihenfolge der Eigenschaften nicht beibehalten wird.
Legacy-Ansatz
Sie haben vielleicht gesehen, dass Leute New-Object
benutzerdefinierte Objekte erstellen.
$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = New-Object -TypeName PSObject -Property $myHashtable
Dieser Weg ist etwas langsamer, kann aber in frühen Versionen von PowerShell die beste Option sein.
Speichern in einer Datei
Ich finde, der beste Weg, eine Hashtabelle in einer Datei zu speichern, ist, sie als JSON zu speichern. Sie können sie dann wieder in eine
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path$myObject = Get-Content -Path $Path | ConvertFrom-Json
Ich behandle weitere Möglichkeiten, Objekte in einer Datei zu speichern, in meinem Artikel über Die vielen Möglichkeiten, Dateien zu lesen und zu schreiben.
Arbeiten mit Eigenschaften
Hinzufügen von Eigenschaften
Sie können mit Add-Member
noch neue Eigenschaften zu Ihrem PSCustomObject
hinzufügen.
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'$myObject.ID
Eigenschaften entfernen
Sie können auch Eigenschaften von einem Objekt entfernen.
$myObject.psobject.properties.remove('ID')
Die psobject
ist eine verborgene Eigenschaft, die Ihnen den Zugriff auf die Metadaten des Basisobjekts ermöglicht.
Eigenschaftsnamen aufzählen
Manchmal benötigen Sie eine Liste aller Eigenschaftsnamen eines Objekts.
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name
Die gleiche Liste können wir auch über die psobject
Eigenschaft erhalten.
$myobject.psobject.properties.name
Dynamischer Zugriff auf Eigenschaften
Ich habe bereits erwähnt, dass man direkt auf Eigenschaftswerte zugreifen kann.
$myObject.Name
Sie können eine Zeichenkette für den Eigenschaftsnamen verwenden und es wird immer noch funktionieren.
$myObject.'Name'
Wir können einen Schritt weiter gehen und eine Variable für den Eigenschaftsnamen verwenden.
$property = 'Name'$myObject.$property
Ich weiß, das sieht seltsam aus, aber es funktioniert.
Konvertieren Sie PSCustomObject in eine Hashtabelle
Um mit dem letzten Abschnitt fortzufahren, können Sie die Eigenschaften dynamisch durchlaufen und daraus eine Hashtabelle erstellen.
$hashtable = @{}foreach( $property in $myobject.psobject.properties.name ){ $hashtable = $myObject.$property}
Prüfen auf Eigenschaften
Wenn Sie wissen müssen, ob eine Eigenschaft existiert, können Sie einfach prüfen, ob diese Eigenschaft einen Wert hat.
if( $null -ne $myObject.ID )
Wenn der Wert aber $null
sein könnte, kann man prüfen, ob er existiert, indem man denpsobject.properties
daraufhin überprüft.
if( $myobject.psobject.properties.match('ID').Count )
Hinzufügen von Objektmethoden
Wenn man eine Skriptmethode zu einem Objekt hinzufügen muss, kann man das mit Add-Member
und einemScriptBlock
tun. Sie müssen die automatische Variable this
verwenden, die das aktuelle Objekt referenziert. Hier ist ascriptblock
, um ein Objekt in eine Hashtabelle zu verwandeln. (derselbe Code wie im letzten Beispiel)
Dann fügen wir sie unserem Objekt als Skripteigenschaft hinzu.
Dann können wir unsere Funktion wie folgt aufrufen:
$myObject.ToHashtable()
Objekte vs. Werttypen
Objekte und Werttypen behandeln Variablenzuweisungen nicht auf die gleiche Weise. Wenn man Werttypen einander zuweist, wird nur der Wert in die neue Variable kopiert.
$first = 1$second = $first$second = 2
In diesem Fall ist $first
die 1 und $second
die 2.
Objektvariablen enthalten eine Referenz auf das eigentliche Objekt. Wenn du ein Objekt einer neuen Variablen zuweist, verweisen sie immer noch auf dasselbe Objekt.
$third = @{Key=3}$fourth = $third$fourth.Key = 4
Da $third
und $fourth
auf dieselbe Instanz eines Objekts verweisen, sind $third.key
und $fourth.Key
beide 4.
psobject.copy()
Wenn man eine echte Kopie eines Objekts braucht, kann man es klonen.
$third = @{Key=3}$fourth = $third.psobject.copy()$fourth.Key = 4
Clone erstellt eine flache Kopie des Objekts. Sie haben jetzt verschiedene Instanzen und $third.key
ist 3 und $fourth.Key
ist 4 in diesem Beispiel.
Ich nenne das eine flache Kopie, weil man verschachtelte Objekte hat. (wo die Eigenschaften andere Objekte enthalten). Es werden nur die Werte der obersten Ebene kopiert. Die untergeordneten Objekte referenzieren sich gegenseitig.
PSTypeName für benutzerdefinierte Objekttypen
Nun, da wir ein Objekt haben, gibt es ein paar weitere Dinge, die wir damit tun können, die vielleicht nicht so offensichtlich sind. Als erstes müssen wir ihm einen PSTypeName
geben. Das ist die gängigste Methode, die ich kenne:
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
Ich habe vor kurzem eine andere Methode entdeckt, die in diesem Beitrag von /u/markekraus beschrieben ist. Ich habe ein wenig nachgeforscht und weitere Beiträge über die Idee von Adam Bertram und Mike Shepard gefunden, in denen sie über diesen Ansatz sprechen, der es erlaubt, ihn inline zu definieren.
$myObject = @{ PSTypeName = 'My.Object' Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}
Ich finde es toll, wie gut das in die Sprache passt. Jetzt, da wir ein Objekt mit einem richtigen Typennamen haben, können wir einige weitere Dinge tun.
Hinweis
Sie können auch benutzerdefinierte PowerShell-Typen mit PowerShell-Klassen erstellen. Weitere Informationen finden Sie unterPowerShell-Klassenübersicht.
Verwenden von DefaultPropertySet (der lange Weg)
PowerShell entscheidet für uns, welche Eigenschaften standardmäßig angezeigt werden sollen. Viele der nativen Befehle haben eine.ps1xml
Formatierungsdatei, die die ganze Arbeit übernimmt. Aus diesem Beitrag von Boe Prox geht hervor, dass es eine weitere Möglichkeit gibt, dies für unser benutzerdefiniertes Objekt nur mit PowerShell zu tun. Wir können ihm einMemberSet
geben, das es verwenden soll.
Wenn mein Objekt jetzt einfach in die Shell fällt, zeigt es standardmäßig nur diese Eigenschaften an.
Update-TypeData mit DefaultPropertySet
Das ist schön, aber ich habe kürzlich eine bessere Möglichkeit gesehen, als ich mirPowerShell unplugged 2016 mit Jeffrey Snover & Don Jones angesehen habe. Jeffrey verwendeteUpdate-TypeData, um die Standardeigenschaften festzulegen.
$TypeData = @{ TypeName = 'My.Object' DefaultDisplayPropertySet = 'Name','Language'}Update-TypeData @TypeData
Das ist so einfach, dass ich es mir fast merken könnte, wenn ich nicht diesen Beitrag als Schnellreferenz hätte. Jetzt kann ich ganz einfach Objekte mit vielen Eigenschaften erstellen und sie trotzdem übersichtlich darstellen, wenn ich sie in der Shell betrachte. Wenn ich auf diese anderen Eigenschaften zugreifen oder sie sehen muss, sind sie immer noch da.
$myObject | Format-List *
Update-TypeData mit ScriptProperty
Etwas anderes, das ich aus diesem Video mitgenommen habe, ist das Erstellen von Skripteigenschaften für Ihre Objekte. Dies ist ein guter Zeitpunkt, um darauf hinzuweisen, dass dies auch für bestehende Objekte funktioniert.
Sie können dies tun, bevor Ihr Objekt erstellt wird oder danach und es wird immer noch funktionieren. Das ist der Unterschied zur Verwendung von Add-Member
mit einer Skripteigenschaft. Wenn Sie Add-Member
auf die oben beschriebene Weise verwenden, gilt es nur für diese spezielle Instanz des Objekts. Dies gilt für alle Objekte mit dieser TypeName
.
Funktionsparameter
Sie können nun diese benutzerdefinierten Typen für Parameter in Ihren Funktionen und Skripten verwenden. Sie können eine Funktion diese benutzerdefinierten Objekte erstellen lassen und sie dann an andere Funktionen übergeben.
param( $Data )
PowerShell verlangt, dass das Objekt den von Ihnen angegebenen Typ hat. Wenn der Typ nicht übereinstimmt, wird automatisch ein Überprüfungsfehler ausgelöst, damit Sie sich den Schritt ersparen, in Ihrem Code darauf zu testen. Ein hervorragendes Beispiel dafür, dass PowerShell das tut, was es am besten kann.
Funktion OutputType
Sie können auch ein OutputType
für Ihre erweiterten Funktionen definieren.
function Get-MyObject{ param ( ...
Der Wert des Attributs OutputType ist nur ein Dokumentationshinweis. Er wird nicht aus dem Funktionscode abgeleitet oder mit der tatsächlichen Funktionsausgabe verglichen.
Der Hauptgrund für die Verwendung eines Ausgabetyps ist, dass die Metainformationen über Ihre Funktion Ihre Absichten widerspiegeln. Dinge wie Get-Command
und Get-Help
, die Ihre Entwicklungsumgebung ausnutzen kann. Wenn du mehr Informationen möchtest, dann schau dir die Hilfe dazu an: about_Functions_OutputTypeAttribute.
Wenn du Pester zum Unit-Test deiner Funktionen verwendest, dann wäre es eine gute Idee, zu überprüfen, ob die Ausgabeobjekte mit deinem OutputType übereinstimmen. Dies könnte Variablen abfangen, die einfach in die Pipe fallen, wenn sie es nicht sollten.
Abschließende Gedanken
Der Kontext dieses Artikels bezog sich auf , aber viele dieser Informationen gelten für Objekte im Allgemeinen.
Ich habe die meisten dieser Funktionen schon einmal im Vorbeigehen gesehen, aber ich habe sie nie als eine Sammlung von Informationen über PSCustomObject
gesehen. Erst in der letzten Woche bin ich über eine weitere Funktion gestolpert und war überrascht, dass ich sie noch nicht gesehen hatte. Ich wollte all diese Ideen zusammenfassen, damit Sie hoffentlich das Gesamtbild sehen und sich ihrer bewußt werden, wenn Sie die Gelegenheit haben, sie zu nutzen. Ich hoffe, Sie haben etwas gelernt und finden einen Weg, dies in Ihre Skripte zu integrieren.