Come posso creare un tipo personalizzato in PowerShell da utilizzare per i miei script?

StackOverflow https://stackoverflow.com/questions/59819

  •  09-06-2019
  •  | 
  •  

Domanda

Mi piacerebbe poter definire e utilizzare un tipo personalizzato in alcuni dei miei script PowerShell.Ad esempio, supponiamo che avessi bisogno di un oggetto che avesse la seguente struttura:

Contact
{
    string First
    string Last
    string Phone
}

Come potrei creare questo in modo da poterlo utilizzare in una funzione come la seguente:

function PrintContact
{
    param( [Contact]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

Qualcosa del genere è possibile o addirittura consigliato in PowerShell?

È stato utile?

Soluzione

La creazione di tipi personalizzati può essere eseguita in PowerShell.
Kirk Munro in realtà ha due ottimi post che descrivono dettagliatamente il processo.

Il libro Windows PowerShell in azione di Manning dispone anche di un esempio di codice per la creazione di un linguaggio specifico del dominio per creare tipi personalizzati.Il libro è eccellente in tutto, quindi lo consiglio davvero.

Se stai solo cercando un modo rapido per eseguire quanto sopra, potresti creare una funzione per creare l'oggetto personalizzato come

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
}

Altri suggerimenti

Prima di PowerShell 3

L'Extensible Type System di PowerShell originariamente non ti consentiva di creare tipi concreti che puoi testare come hai fatto nel tuo parametro.Se non hai bisogno di quel test, puoi tranquillamente utilizzare uno qualsiasi degli altri metodi menzionati sopra.

Se desideri un tipo reale a cui puoi eseguire il cast o il controllo del tipo, come nel tuo script di esempio...Esso non può essere fatto senza scriverlo in C# o VB.net e compilarlo.In PowerShell 2, puoi utilizzare il comando "Add-Type" per farlo in modo abbastanza semplice:

add-type @"
public struct contact {
   public string First;
   public string Last;
   public string Phone;
}
"@

Nota storica:In PowerShell 1 era ancora più difficile.Dovevi usare manualmente CodeDom, c'è una funzione molto vecchia nuova-struttura script su PoshCode.org che aiuterà.Il tuo esempio diventa:

New-Struct Contact @{
    First=[string];
    Last=[string];
    Phone=[string];
}

Utilizzando Add-Type O New-Struct ti permetterà di testare effettivamente la classe nel tuo param([Contact]$contact) e crearne di nuovi utilizzando $contact = new-object Contact e così via...

In PowerShell 3

Se non hai bisogno di una classe "reale" a cui puoi trasmettere, non devi utilizzare il modo Aggiungi membro Steven e altri hanno dimostrato Sopra.

A partire da PowerShell 2 è possibile utilizzare il parametro -Property per New-Object:

$Contact = New-Object PSObject -Property @{ First=""; Last=""; Phone="" }

E in PowerShell 3 abbiamo la possibilità di utilizzare il file PSCustomObject acceleratore per aggiungere un TypeName:

[PSCustomObject]@{
    PSTypeName = "Contact"
    First = $First
    Last = $Last
    Phone = $Phone
}

Stai ancora ricevendo un solo oggetto, quindi dovresti creare un file New-Contact per assicurarti che ogni oggetto risulti uguale, ma ora puoi facilmente verificare che un parametro "sia" uno di questi tipi decorando un parametro con il PSTypeName attributo:

function PrintContact
{
    param( [PSTypeName("Contact")]$contact )
    "Customer Name is " + $contact.First + " " + $contact.Last
    "Customer Phone is " + $contact.Phone 
}

In PowerShell 5

In PowerShell 5 tutto cambia e finalmente ce l'abbiamo fatta class E enum come parole chiave del linguaggio per definire i tipi (non esiste struct ma va bene):

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone

    # optionally, have a constructor to 
    # force properties to be set:
    Contact($First, $Last, $Phone) {
       $this.First = $First
       $this.Last = $Last
       $this.Phone = $Phone
    }
}

Abbiamo anche un nuovo modo di creare oggetti senza utilizzare New-Object: [Contact]::new() -- infatti, se mantieni la tua classe semplice e non definisci un costruttore, puoi creare oggetti lanciando una tabella hash (anche se senza un costruttore non ci sarebbe modo di imporre che tutte le proprietà debbano essere impostate):

class Contact
{
    # Optionally, add attributes to prevent invalid values
    [ValidateNotNullOrEmpty()][string]$First
    [ValidateNotNullOrEmpty()][string]$Last
    [ValidateNotNullOrEmpty()][string]$Phone
}

$C = [Contact]@{
   First = "Joel"
   Last = "Bennett"
}

Questo è il metodo di scelta rapida:

$myPerson = "" | Select-Object First,Last,Phone

La risposta di Steven Murawski è ottima, tuttavia mi piace l'oggetto di selezione più breve (o meglio solo l'oggetto di selezione più ordinato invece di utilizzare la sintassi di aggiunta membro):

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
}

Sorpreso che nessuno abbia menzionato questa semplice opzione (vs 3 o successiva) per creare oggetti personalizzati:

[PSCustomObject]@{
    First = $First
    Last = $Last
    Phone = $Phone
}

Il tipo sarà PSCustomObject, ma non un vero tipo personalizzato.Ma è probabilmente il modo più semplice per creare un oggetto personalizzato.

Esiste il concetto di PSObject e Add-Member che potresti utilizzare.

$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"

Questo produce come:

[8] » $contact

First                                       Last                                       Phone
-----                                       ----                                       -----
John                                        Doe                                        123-4567

L'altra alternativa (di cui sono a conoscenza) è definire un tipo in C#/VB.NET e caricare l'assembly in PowerShell per utilizzarlo direttamente.

Questo comportamento è decisamente incoraggiato perché consente ad altri script o sezioni dello script di funzionare con un oggetto reale.

Ecco il percorso difficile per creare tipi personalizzati e archiviarli in una raccolta.

$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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top