Erstens, wie dies führt zu meiner Frage, I' ll beginnen mit der Feststellung, dass I' ve arbeitete mit XML ein faires Bit in PowerShell, und wie ich Daten aus XML-Dateien lesen können, schnell, in Arrays von benutzerdefinierten Objekten. Zum Beispiel, wenn ich die folgende XML-Datei hatte:
<stuff>
<item name="Joe" age="32">
<info>something about him</info>
</item>
<item name="Sue" age="29">
<info>something about her</info>
</item>
<item name="Cat" age="12">
<info>something else</info>
</item>
</stuff>
Und wenn ich sie einfach einlese, etwa so:
[xml]$myxml = Get-Content .\my.xml
Dann kann ich ein Array mit meinen Artikeln wie folgt erhalten:
[array]$myitems = $myxml.stuff.Item
$myitems
name age info
---- --- ----
Joe 32 something about him
Sue 29 something about her
Cat 12 something else
So, nun meine Frage:
Wie kann ich eine ähnliche Struktur eines Arrays von benutzerdefinierten Objekten erstellen und sie in meinem Skript initialisieren, ohne eine Datei zu lesen?
Ich kann viele Schleifen machen und/oder viele einzelne Objekte erstellen/initialisieren, und dann eines nach dem anderen zu einem Array hinzufügen...
Aber es scheint, dass es einen Weg geben sollte, diese Erstellung/Initialisierung auf eine einfachere Weise durchzuführen. Beachten Sie, dass der Schlüssel hier, ist, dass meine benutzerdefinierten Objekte mehr als zwei Elemente haben (sonst, I'd haben einen Hash verwendet).
Ich habe sogar versucht, eine große XML-Zeichenkette zu erstellen und Select-XML zu verwenden, aber ich habe die Syntax einfach nicht hinbekommen (wenn das überhaupt der richtige Weg ist).
Ich würde etwas in dieser Richtung tun:
$myitems =
@([pscustomobject]@{name="Joe";age=32;info="something about him"},
[pscustomobject]@{name="Sue";age=29;info="something about her"},
[pscustomobject]@{name="Cat";age=12;info="something else"})
Beachten Sie, dass dies nur in PowerShell 3 funktioniert, aber da Sie die Version in Ihrer Frage nicht erwähnt haben, nehme ich an, dass dies für Sie keine Rolle spielt.
Aktualisierung
In Kommentaren wurde erwähnt, dass Sie Folgendes tun können:
$younger = $myitems | Where-Object { $_.age -lt 20 }
Write-Host "people younger than 20: $($younger.Length)"
Sie erhalten nicht 1
wie Sie vielleicht erwarten. Das passiert, wenn ein einzelnes pscustomobject
zurückgegeben wird. Für die meisten anderen Objekte in der PowerShell ist dies kein Problem, da sie Surrogateigenschaften für Length
und Count
haben. Leider hat pscustomobject
dies nicht. Dies wurde in PowerShell 6.1.0 behoben. Sie können dieses Problem umgehen, indem Sie den Operator @()
verwenden:
$younger = @($myitems | Where-Object { $_.age -lt 20 })
Weitere Hintergrundinformationen finden Sie hier und hier.
Aktualisierung 2
In PowerShell 5 kann man Classes verwenden, um eine ähnliche Funktionalität zu erreichen. Zum Beispiel können Sie eine Klasse wie diese definieren:
class Person {
[string]$name
[int]$age
[string]$info; `
`
Person(
[string]$name,
[int]$age,
[string]$info
){
$this.name = $name
$this.age = $age
$this.info = $info
}
}
Die Backticks dienen dazu, die Klasse zu kopieren und in die Befehlszeile einzufügen; sie sind in einem Skript nicht erforderlich. Sobald die Klasse definiert ist, können Sie ein Array auf die übliche Weise erstellen:
$myitems =@([Person]::new("Joe",32,"something about him"),
[Person]::new("Sue",29,"something about her"),
[Person]::new("Cat",12,"something else"))
Beachten Sie, dass dieser Weg auch in PowerShell 5 nicht den Nachteil hat, der im vorherigen Update erwähnt wurde.
Update 3
Sie können auch ein Klassenobjekt mit einer Hashtabelle initialisieren, ähnlich wie im ersten Beispiel. Dazu müssen Sie sicherstellen, dass ein Standard-Konstruktor definiert ist. Wenn Sie keine Konstruktoren angeben, wird einer für Sie erstellt, aber wenn Sie einen Nicht-Standard-Konstruktor angeben, wird der Standard-Konstruktor nicht vorhanden sein und Sie müssen ihn explizit definieren. Hier ist ein Beispiel mit einem Standardkonstruktor, der automatisch erstellt wird:
class Person {
[string]$name
[int]$age
[string]$info;
}
Damit können Sie:
$person = @([Person]@{name='Kevin';age=36;info="something about him"}
[Person]@{name='Sue';age=29;info="something about her"}
[Person]@{name='Cat';age=12;info="something else"})
Das ist etwas ausführlicher, aber auch etwas deutlicher. Vielen Dank an @js2010 für den Hinweis darauf.
Hier finden Sie eine prägnante Methode zum Initialisieren eines Arrays von benutzerdefinierten Objekten in PowerShell.
> $body = @( @{ Prop1="1"; Prop2="2"; Prop3="3" }, @{ Prop1="1"; Prop2="2"; Prop3="3" } )
> $body
Name Value
---- -----
Prop2 2
Prop1 1
Prop3 3
Prop2 2
Prop1 1
Prop3 3
Vielleicht meinen Sie so? Ich möchte ein Objekt erstellen und Format-Table verwenden:
PS C:\Users\Joel> $array = @()
PS C:\Users\Joel> $object = New-Object -TypeName PSObject
PS C:\Users\Joel> $object | Add-Member -Name 'Name' -MemberType Noteproperty -Value 'Joe'
PS C:\Users\Joel> $object | Add-Member -Name 'Age' -MemberType Noteproperty -Value 32
PS C:\Users\Joel> $object | Add-Member -Name 'Info' -MemberType Noteproperty -Value 'something about him'
PS C:\Users\Joel> $array += $object
PS C:\Users\Joel> $array | Format-Table
Name Age Info
---- --- ----
Joe 32 something about him
Dadurch werden alle Objekte im Array entsprechend ihrer Eigenschaften in Spalten angeordnet.
Tipp: Mit -auto
wird die Tabelle besser dimensioniert
PS C:\Users\Joel> $array | Format-Table -Auto
Name Age Info
---- --- ----
Joe 32 something about him
Sie können auch angeben, welche Eigenschaften Sie in der Tabelle haben möchten. Trennen Sie dazu die einzelnen Eigenschaftsnamen durch ein Komma:
PS C:\Users\Joel> $array | Format-Table Name, Age -Auto
Name Age
---- ---
Joe 32