Vor PowerShell 3
Mit dem Extensible Type System von PowerShell konnten Sie ursprünglich keine konkreten Typen erstellen, die Sie anhand der Parameter testen können. Wenn Sie diesen Test nicht benötigen, können Sie eine der anderen oben genannten Methoden anwenden.
Wenn Sie einen tatsächlichen Typ möchten, den Sie wie in Ihrem Beispielskript umwandeln oder mit dem Sie ihn überprüfen können, können Sie dies nicht tun, ohne ihn in C # oder VB.net zu schreiben und zu kompilieren. In PowerShell 2 können Sie den Befehl "Typ hinzufügen" verwenden, um dies ganz einfach zu tun:
add-type @"
public struct contact {
public string First;
public string Last;
public string Phone;
}
"@
Historischer Hinweis : In PowerShell 1 war es noch schwieriger. Sie mussten CodeDom manuell verwenden, es gibt ein sehr altes Funktions- New- Struct - Skript auf PoshCode.org, das helfen wird. Ihr Beispiel wird:
New-Struct Contact @{
First=[string];
Last=[string];
Phone=[string];
}
Mit Add-Type
oder New-Struct
können Sie die Klasse in Ihrer Klasse testen param([Contact]$contact)
und neue erstellen, indem Sie $contact = new-object Contact
usw. verwenden ...
In PowerShell 3
Wenn Sie keine "echte" Klasse benötigen, in die Sie umwandeln können, müssen Sie nicht die Add-Member-Methode verwenden, die Steven und andere oben demonstriert haben .
Seit PowerShell 2 können Sie den Parameter -Property für New-Object verwenden:
$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }
In PowerShell 3 haben wir die Möglichkeit, mithilfe des PSCustomObject
Beschleunigers einen Typnamen hinzuzufügen:
[PSCustomObject]@{
PSTypeName = "Contact"
First = $First
Last = $Last
Phone = $Phone
}
Sie erhalten immer noch nur ein einzelnes Objekt. Sie sollten daher eine New-Contact
Funktion erstellen, um sicherzustellen, dass jedes Objekt gleich ausgegeben wird. Sie können jetzt jedoch leicht überprüfen, ob ein Parameter "ist" einer dieser Typen ist, indem Sie einen Parameter mit dem folgenden PSTypeName
Attribut dekorieren :
function PrintContact
{
param( [PSTypeName("Contact")]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
In PowerShell 5
In PowerShell 5 ändert sich alles und wir haben endlich class
und enum
als Sprachschlüsselwörter zum Definieren von Typen (es gibt keine, struct
aber das ist in Ordnung):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
Contact($First, $Last, $Phone) {
$this.First = $First
$this.Last = $Last
$this.Phone = $Phone
}
}
Wir haben auch eine neue Möglichkeit zum Erstellen von Objekten ohne Verwendung New-Object
: [Contact]::new()
- Wenn Sie Ihre Klasse einfach halten und keinen Konstruktor definieren, können Sie Objekte erstellen, indem Sie eine Hashtabelle umwandeln (obwohl es ohne Konstruktor keine Möglichkeit gibt um zu erzwingen, dass alle Eigenschaften festgelegt werden müssen):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
}
$C = [Contact]@{
First = "Joel"
Last = "Bennett"
}
Add-Type
? Es scheint in PowerShell 2 unter Win 2008 R2 zu funktionieren. Angenommen, ich definierecontact
mitAdd-Type
wie in Ihrer Antwort und erstelle dann eine Instanz :$con = New-Object contact -Property @{ First="a"; Last="b"; Phone="c" }
. Dann funktioniert das Aufrufen dieser Funktion :function x([contact]$c) { Write-Host ($c | Out-String) $c.GetType() }
, das Aufrufen dieser Funktion schlägt jedoch fehlx([doesnotexist]$c) { Write-Host ($c | Out-String) $c.GetType() }
. Der Aufrufx 'abc'
schlägt auch mit einer entsprechenden Fehlermeldung zum Casting fehl. Getestet in PS 2 und 4.Add-Type
@ jpmc26 erstellt wurden. Ich habe gesagt, dass Sie dies nicht ohne Kompilieren tun können (dh ohne es in C # zu schreiben und aufzurufenAdd-Type
). Natürlich können Sie von PS3 aus - es gibt ein[PSTypeName("...")]
Attribut, mit dem Sie den Typ als Zeichenfolge angeben können, das das Testen gegen PSCustomObjects mit festgelegten PSTypeNames unterstützt ...Das Erstellen benutzerdefinierter Typen kann in PowerShell erfolgen.
Kirk Munro hat tatsächlich zwei großartige Beiträge, die den Prozess gründlich beschreiben.
Das Buch Windows PowerShell In Action von Manning enthält auch ein Codebeispiel zum Erstellen einer domänenspezifischen Sprache zum Erstellen benutzerdefinierter Typen. Das Buch ist rundum ausgezeichnet, daher kann ich es nur empfehlen.
Wenn Sie nur nach einer schnellen Möglichkeit suchen, dies zu tun, können Sie eine Funktion zum Erstellen eines benutzerdefinierten Objekts erstellen
function New-Person() { param ($FirstName, $LastName, $Phone) $person = new-object PSObject $person | add-member -type NoteProperty -Name First -Value $FirstName $person | add-member -type NoteProperty -Name Last -Value $LastName $person | add-member -type NoteProperty -Name Phone -Value $Phone return $person }
quelle
Dies ist die Verknüpfungsmethode:
$myPerson = "" | Select-Object First,Last,Phone
quelle
$myPerson = 1 | Select First,Last,Phone
NoteProperty
derstring
Typ, ist es eine wieProperty
auch immer geartete Sie in dem Objekt zugewiesen haben. Dies ist schnell und erledigt den Job.Steven Murawskis Antwort ist großartig, aber ich mag das kürzere (oder besser gesagt das sauberere Auswahlobjekt, anstatt die Syntax für Add-Member zu verwenden):
function New-Person() { param ($FirstName, $LastName, $Phone) $person = new-object PSObject | select-object First, Last, Phone $person.First = $FirstName $person.Last = $LastName $person.Phone = $Phone return $person }
quelle
New-Object
wird nicht einmal benötigt. Dies wird das gleiche tun:... = 1 | select-object First, Last, Phone
int
Weges: 1) es arbeitet schneller, nicht viel, aber für diese spezielle FunktionNew-Person
beträgt der Unterschied 20%; 2) es ist anscheinend einfacher zu tippen. Gleichzeitig habe ich mit diesem Ansatz praktisch überall keine Nachteile gesehen. Aber ich stimme zu: Es kann einige seltene Fälle geben, in denen PSCustomObject besser ist.Überrascht erwähnte niemand diese einfache Option (vs 3 oder höher) zum Erstellen von benutzerdefinierten Objekten:
[PSCustomObject]@{ First = $First Last = $Last Phone = $Phone }
Der Typ ist PSCustomObject, jedoch kein tatsächlicher benutzerdefinierter Typ. Aber es ist wahrscheinlich der einfachste Weg, ein benutzerdefiniertes Objekt zu erstellen.
quelle
Es gibt das Konzept von PSObject und Add-Member, das Sie verwenden können.
$contact = New-Object PSObject $contact | Add-Member -memberType NoteProperty -name "First" -value "John" $contact | Add-Member -memberType NoteProperty -name "Last" -value "Doe" $contact | Add-Member -memberType NoteProperty -name "Phone" -value "123-4567"
Dies gibt aus wie:
[8] » $contact First Last Phone ----- ---- ----- John Doe 123-4567
Die andere Alternative (die mir bekannt ist) besteht darin, einen Typ in C # / VB.NET zu definieren und diese Assembly zur direkten Verwendung in PowerShell zu laden.
Dieses Verhalten wird definitiv empfohlen, da andere Skripte oder Abschnitte Ihres Skripts mit einem tatsächlichen Objekt arbeiten können.
quelle
Hier ist der schwierige Weg, um benutzerdefinierte Typen zu erstellen und in einer Sammlung zu speichern.
$Collection = @() $Object = New-Object -TypeName PSObject $Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail') Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "John" Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe" Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "123-4567" $Collection += $Object $Object = New-Object -TypeName PSObject $Object.PsObject.TypeNames.Add('MyCustomType.Contact.Detail') Add-Member -InputObject $Object -memberType NoteProperty -name "First" -value "Jeanne" Add-Member -InputObject $Object -memberType NoteProperty -name "Last" -value "Doe" Add-Member -InputObject $Object -memberType NoteProperty -name "Phone" -value "765-4321" $Collection += $Object Write-Ouput -InputObject $Collection
quelle
Hier ist eine weitere Option, die eine ähnliche Idee wie die von Jaykul erwähnte PSTypeName-Lösung verwendet (und daher auch PSv3 oder höher erfordert).
Beispiel
Person.Types.ps1xml
:<?xml version="1.0" encoding="utf-8" ?> <Types> <Type> <Name>StackOverflow.Example.Person</Name> <Members> <ScriptMethod> <Name>Initialize</Name> <Script> Param ( [Parameter(Mandatory = $true)] [string]$GivenName , [Parameter(Mandatory = $true)] [string]$Surname ) $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName $this | Add-Member -MemberType 'NoteProperty' -Name 'Surname' -Value $Surname </Script> </ScriptMethod> <ScriptMethod> <Name>SetGivenName</Name> <Script> Param ( [Parameter(Mandatory = $true)] [string]$GivenName ) $this | Add-Member -MemberType 'NoteProperty' -Name 'GivenName' -Value $GivenName -Force </Script> </ScriptMethod> <ScriptProperty> <Name>FullName</Name> <GetScriptBlock>'{0} {1}' -f $this.GivenName, $this.Surname</GetScriptBlock> </ScriptProperty> <!-- include properties under here if we don't want them to be visible by default <MemberSet> <Name>PSStandardMembers</Name> <Members> </Members> </MemberSet> --> </Members> </Type> </Types>
Update-TypeData -AppendPath .\Person.Types.ps1xml
$p = [PSCustomType]@{PSTypeName='StackOverflow.Example.Person'}
$p.Initialize('Anne', 'Droid')
$p | Format-Table -AutoSize
$p.SetGivenName('Dan')
$p | Format-Table -AutoSize
Erläuterung
PS1XML
oderAdd-Member
sind beschränkt aufNoteProperty
,AliasProperty
,ScriptProperty
,CodeProperty
,ScriptMethod
, undCodeMethod
(oderPropertySet
/MemberSet
, obwohl diejenigen , unterliegen den gleichen Einschränkungen). Alle diese Eigenschaften sind schreibgeschützt.ScriptMethod
wir die obige Einschränkung betrügen. ZB Wir können eine Methode (z. B.Initialize
) definieren, die neue Eigenschaften erstellt und deren Werte für uns festlegt. So stellen Sie sicher, dass unser Objekt alle Eigenschaften hat, die wir benötigen, damit unsere anderen Skripte funktionieren.SetGivenName
.Dieser Ansatz ist nicht für alle Szenarien ideal. Dies ist jedoch nützlich, um benutzerdefinierten Typen klassenähnliches Verhalten hinzuzufügen. / Kann in Verbindung mit anderen in den anderen Antworten genannten Methoden verwendet werden. In der realen Welt würde ich wahrscheinlich nur die
FullName
Eigenschaft in PS1XML definieren und dann eine Funktion verwenden, um das Objekt mit den erforderlichen Werten zu erstellen, wie folgt:Mehr Info
Schauen Sie sich die Dokumentation oder die OOTB-Datei an,
Get-Content $PSHome\types.ps1xml
um sich inspirieren zu lassen.# have something like this defined in my script so we only try to import the definition once. # the surrounding if statement may be useful if we're dot sourcing the script in an existing # session / running in ISE / something like that if (!(Get-TypeData 'StackOverflow.Example.Person')) { Update-TypeData '.\Person.Types.ps1xml' } # have a function to create my objects with all required parameters # creating them from the hash table means they're PROPERties; i.e. updatable without calling a # setter method (note: recall I said above that in this scenario I'd remove their definition # from the PS1XML) function New-SOPerson { [CmdletBinding()] [OutputType('StackOverflow.Example.Person')] Param ( [Parameter(Mandatory)] [string]$GivenName , [Parameter(Mandatory)] [string]$Surname ) ([PSCustomObject][Ordered]@{ PSTypeName = 'StackOverflow.Example.Person' GivenName = $GivenName Surname = $Surname }) } # then use my new function to generate the new object $p = New-SOPerson -GivenName 'Simon' -Surname 'Borg' # and thanks to the type magic... FullName exists :) Write-Information "$($p.FullName) was created successfully!" -InformationAction Continue
quelle