Avant PowerShell 3
Le système de type extensible de PowerShell ne vous permettait pas à l'origine de créer des types concrets que vous pouvez tester comme vous l'avez fait dans votre paramètre. Si vous n'avez pas besoin de ce test, vous êtes d'accord avec l'une des autres méthodes mentionnées ci-dessus.
Si vous voulez un type réel avec lequel vous pouvez transtyper ou vérifier le type, comme dans votre exemple de script ... cela ne peut pas être fait sans l'écrire en C # ou VB.net et le compiler. Dans PowerShell 2, vous pouvez utiliser la commande "Add-Type" pour le faire assez simplement:
add-type @"
public struct contact {
public string First;
public string Last;
public string Phone;
}
"@
Note historique : dans PowerShell 1, c'était encore plus difficile. Vous deviez utiliser manuellement CodeDom, il y a un très ancienscript defonction new-struct sur PoshCode.org qui vous aidera. Votre exemple devient:
New-Struct Contact @{
First=[string];
Last=[string];
Phone=[string];
}
Utiliser Add-Type
ou New-Struct
vous permettra de tester la classe dans votre param([Contact]$contact)
et d'en créer de nouvelles en utilisant $contact = new-object Contact
et ainsi de suite ...
Dans PowerShell 3
Si vous n'avez pas besoin d'une "vraie" classe dans laquelle vous pouvez effectuer un cast, vous n'avez pas besoin d'utiliser la méthode d'ajout de membre que Steven et d'autres ont démontrée ci-dessus.
Depuis PowerShell 2, vous pouvez utiliser le paramètre -Property pour New-Object:
$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }
Et dans PowerShell 3, nous avons la possibilité d'utiliser l' PSCustomObject
accélérateur pour ajouter un TypeName:
[PSCustomObject]@{
PSTypeName = "Contact"
First = $First
Last = $Last
Phone = $Phone
}
Vous n'obtenez toujours qu'un seul objet, vous devez donc créer une New-Contact
fonction pour vous assurer que chaque objet sort de la même manière, mais vous pouvez maintenant facilement vérifier qu'un paramètre "est" l'un de ces types en décorant un paramètre avec l' PSTypeName
attribut:
function PrintContact
{
param( [PSTypeName("Contact")]$contact )
"Customer Name is " + $contact.First + " " + $contact.Last
"Customer Phone is " + $contact.Phone
}
Dans PowerShell 5
Dans PowerShell 5, tout change et nous avons finalement obtenu class
etenum
tant que mots-clés de langage pour définir les types (il n'y a pas struct
mais c'est ok):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
Contact($First, $Last, $Phone) {
$this.First = $First
$this.Last = $Last
$this.Phone = $Phone
}
}
Nous avons également une nouvelle façon de créer des objets sans utiliser New-Object
: [Contact]::new()
- en fait, si vous gardez votre classe simple et ne définissez pas de constructeur, vous pouvez créer des objets en castant une table de hachage (bien que sans constructeur, il n'y aurait aucun moyen pour garantir que toutes les propriétés doivent être définies):
class Contact
{
[ValidateNotNullOrEmpty()][string]$First
[ValidateNotNullOrEmpty()][string]$Last
[ValidateNotNullOrEmpty()][string]$Phone
}
$C = [Contact]@{
First = "Joel"
Last = "Bennett"
}
Add-Type
? Il semble fonctionner dans PowerShell 2 sur Win 2008 R2. Dire que je définis lecontact
utilisantAdd-Type
comme dans votre réponse, puis créer une instance:$con = New-Object contact -Property @{ First="a"; Last="b"; Phone="c" }
. Ensuite , l' appel de cette fonction fonctionne:function x([contact]$c) { Write-Host ($c | Out-String) $c.GetType() }
, mais d' appeler cette fonction échoue,x([doesnotexist]$c) { Write-Host ($c | Out-String) $c.GetType() }
. L'appelx 'abc'
échoue également avec un message d'erreur approprié concernant la diffusion. Testé en PS 2 et 4.Add-Type
@ jpmc26, ce que j'ai dit, c'est que vous ne pouvez pas le faire sans compiler (c'est-à-dire sans l'écrire en C # et appelerAdd-Type
). Bien sûr, à partir de PS3, vous pouvez - il existe un[PSTypeName("...")]
attribut qui vous permet de spécifier le type sous forme de chaîne, qui prend en charge les tests contre PSCustomObjects avec le jeu PSTypeNames ...La création de types personnalisés peut être effectuée dans PowerShell.
Kirk Munro a en fait deux excellents articles qui détaillent le processus à fond.
Le livre Windows PowerShell en action de Manning propose également un exemple de code permettant de créer un langage spécifique à un domaine pour créer des types personnalisés. Le livre est excellent tout autour, donc je le recommande vraiment.
Si vous cherchez simplement un moyen rapide de faire ce qui précède, vous pouvez créer une fonction pour créer l'objet personnalisé comme
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 }
la source
Voici la méthode de raccourci:
$myPerson = "" | Select-Object First,Last,Phone
la source
$myPerson = 1 | Select First,Last,Phone
NoteProperty
dustring
type, il estProperty
de quelque type que vous avez attribué à l'objet. Ceci est rapide et fait le travail cependant.La réponse de Steven Murawski est excellente, mais j'aime le plus court (ou plutôt juste l'objet de sélection plus net au lieu d'utiliser la syntaxe d'ajout de membre):
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 }
la source
New-Object
n'est même pas nécessaire. Cela fera de même:... = 1 | select-object First, Last, Phone
int
manière: 1) cela fonctionne plus vite, pas beaucoup, mais pour cette fonction particulière,New-Person
la différence est de 20%; 2) il est apparemment plus facile à taper. En même temps, en utilisant cette approche pratiquement partout, je n'ai jamais vu d'inconvénients. Mais je suis d'accord: il peut y avoir de rares cas où PSCustomObject est un peu mieux.Surpris, personne n'a mentionné cette option simple (vs 3 ou version ultérieure) pour créer des objets personnalisés:
[PSCustomObject]@{ First = $First Last = $Last Phone = $Phone }
Le type sera PSCustomObject, mais pas un type personnalisé réel. Mais c'est probablement le moyen le plus simple de créer un objet personnalisé.
la source
Il y a le concept de PSObject et Add-Member que vous pouvez utiliser.
$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"
Cela produit comme:
[8] » $contact First Last Phone ----- ---- ----- John Doe 123-4567
L'autre alternative (dont je suis conscient) consiste à définir un type dans C # / VB.NET et à charger cet assembly dans PowerShell pour une utilisation directe.
Ce comportement est définitivement encouragé car il permet à d'autres scripts ou sections de votre script de fonctionner avec un objet réel.
la source
Voici le chemin difficile pour créer des types personnalisés et les stocker dans une collection.
$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
la source
Voici une autre option, qui utilise une idée similaire à la solution PSTypeName mentionnée par Jaykul (et nécessite donc également PSv3 ou supérieur).
Exemple
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
Explication
PS1XML
ouAdd-Member
sont limités àNoteProperty
,AliasProperty
,ScriptProperty
,CodeProperty
,ScriptMethod
etCodeMethod
(ouPropertySet
/MemberSet
, bien que ceux -ci sont soumis aux mêmes restrictions). Toutes ces propriétés sont en lecture seule.ScriptMethod
nous pouvons tricher la restriction ci-dessus. Par exemple, nous pouvons définir une méthode (par exempleInitialize
) qui crée de nouvelles propriétés, en définissant leurs valeurs pour nous; garantissant ainsi que notre objet possède toutes les propriétés dont nous avons besoin pour que nos autres scripts fonctionnent.SetGivenName
.Cette approche n'est pas idéale pour tous les scénarios; mais est utile pour ajouter des comportements de classe à des types personnalisés / peut être utilisé en conjonction avec d'autres méthodes mentionnées dans les autres réponses. Par exemple, dans le monde réel, je définirais probablement uniquement la
FullName
propriété dans PS1XML, puis utiliserais une fonction pour créer l'objet avec les valeurs requises, comme ceci:Plus d'informations
Jetez un œil à la documentation ou au fichier de type OOTB
Get-Content $PSHome\types.ps1xml
pour vous inspirer.# 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
la source