¿Cómo creo un tipo personalizado en PowerShell para que lo utilicen mis scripts?

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

  •  09-06-2019
  •  | 
  •  

Pregunta

Me gustaría poder definir y utilizar un tipo personalizado en algunos de mis scripts de PowerShell.Por ejemplo, supongamos que necesito un objeto que tenga la siguiente estructura:

Contact
{
    string First
    string Last
    string Phone
}

¿Cómo haría para crear esto para poder usarlo en funciones como las siguientes?

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

¿Es posible algo como esto, o incluso se recomienda en PowerShell?

¿Fue útil?

Solución

La creación de tipos personalizados se puede realizar en PowerShell.
Kirk Munro en realidad tiene dos publicaciones excelentes que detallan detalladamente el proceso.

El libro Windows PowerShell en acción por Manning También tiene un ejemplo de código para crear un lenguaje específico de dominio para crear tipos personalizados.El libro es excelente en todos los aspectos, así que realmente lo recomiendo.

Si solo está buscando una forma rápida de hacer lo anterior, puede crear una función para crear el objeto personalizado como

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
}

Otros consejos

Antes de PowerShell 3

El sistema de tipos extensibles de PowerShell originalmente no le permitía crear tipos concretos que pudiera probar con la forma en que lo hizo en su parámetro.Si no necesita esa prueba, está bien con cualquiera de los otros métodos mencionados anteriormente.

Si desea un tipo real al que pueda transmitir o verificar el tipo, como en su secuencia de comandos de ejemplo...él no puedo se puede hacer sin escribirlo en C# o VB.net y compilarlo.En PowerShell 2, puedes usar el comando "Agregar tipo" para hacerlo de manera bastante simple:

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

Nota histórica:En PowerShell 1 fue aún más difícil.Tenías que usar CodeDom manualmente, hay una función muy antigua. nueva estructura script en PoshCode.org que le ayudará.Tu ejemplo se convierte en:

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

Usando Add-Type o New-Struct te permitirá probar la clase en tu param([Contact]$contact) y hacer otros nuevos usando $contact = new-object Contact etcétera...

En PowerShell 3

Si no necesita una clase "real" a la que pueda transmitir, no tiene que usar la forma Agregar miembro para que Steven y otros han demostrado arriba.

Desde PowerShell 2 puedes usar el parámetro -Property para New-Object:

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

Y en PowerShell 3, tenemos la posibilidad de utilizar el PSCustomObject acelerador para agregar un TypeName:

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

Aún obtienes un solo objeto, por lo que debes hacer un New-Contact función para asegurarse de que todos los objetos salgan iguales, pero ahora puede verificar fácilmente que un parámetro "es" uno de esos tipos decorando un parámetro con el PSTypeName atributo:

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

En PowerShell 5

En PowerShell 5 todo cambia y finalmente conseguimos class y enum como palabras clave del idioma para definir tipos (no hay struct pero eso esta bien):

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
    }
}

También tenemos una nueva forma de crear objetos sin usar New-Object: [Contact]::new() -- de hecho, si mantienes tu clase simple y no defines un constructor, puedes crear objetos al convertir una tabla hash (aunque sin un constructor, no habría manera de exigir que se establezcan todas las propiedades):

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

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

Este es el método abreviado:

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

La respuesta de Steven Murawski es excelente, sin embargo, me gusta la más corta (o más bien, la selección de objeto más ordenada en lugar de usar la sintaxis de agregar miembro):

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
}

Me sorprende que nadie haya mencionado esta opción simple (vs 3 o posterior) para crear objetos personalizados:

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

El tipo será PSCustomObject, aunque no un tipo personalizado real.Pero probablemente sea la forma más sencilla de crear un objeto personalizado.

Existe el concepto de PSObject y Add-Member que podría utilizar.

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

Esto produce como:

[8] » $contact

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

La otra alternativa (que yo sepa) es definir un tipo en C#/VB.NET y cargar ese ensamblado en PowerShell para usarlo directamente.

Definitivamente se recomienda este comportamiento porque permite que otros scripts o secciones de su script funcionen con un objeto real.

Este es el camino difícil para crear tipos personalizados y almacenarlos en una colección.

$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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top