Pergunta

Gostaria de poder definir e usar um tipo personalizado em alguns dos meus scripts do PowerShell.Por exemplo, vamos fingir que eu preciso de um objeto que tenha a seguinte estrutura:

Contact
{
    string First
    string Last
    string Phone
}

Como eu criaria isso para poder usá-lo em uma função como a seguinte:

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

Algo assim é possível ou mesmo recomendado no PowerShell?

Foi útil?

Solução

A criação de tipos personalizados pode ser feita no PowerShell.
Kirk Munro, na verdade, tem duas ótimas postagens que detalham detalhadamente o processo.

O livro Windows PowerShell em ação por Manning também possui um exemplo de código para criar uma linguagem específica de domínio para criar tipos personalizados.O livro é excelente em todos os aspectos, então eu realmente o recomendo.

Se você está apenas procurando uma maneira rápida de fazer o que foi dito acima, você pode criar uma função para criar o 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
}

Outras dicas

Antes do PowerShell 3

O Extensible Type System do PowerShell originalmente não permitia criar tipos concretos que você pudesse testar da maneira que fez em seu parâmetro.Se você não precisar desse teste, poderá usar qualquer um dos outros métodos mencionados acima.

Se você deseja um tipo real para o qual possa converter ou verificar o tipo, como no seu script de exemplo ...isto não pode ser feito sem escrever em C# ou VB.net e compilar.No PowerShell 2, você pode usar o comando “Add-Type” para fazer isso de forma bastante simples:

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

Nota Histórica:No PowerShell 1 foi ainda mais difícil.Você teve que usar o CodeDom manualmente, existe uma função muito antiga nova estrutura script em PoshCode.org que ajudará.Seu exemplo se torna:

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

Usando Add-Type ou New-Struct permitirá que você realmente teste a classe em seu param([Contact]$contact) e faça novos usando $contact = new-object Contact e assim por diante...

No PowerShell 3

Se você não precisa de uma classe "real" para a qual possa transmitir, não precisa usar o método Add-Member que Steven e outros demonstraram acima.

Desde o PowerShell 2 você pode usar o parâmetro -Property para New-Object:

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

E no PowerShell 3, conseguimos usar o PSCustomObject acelerador para adicionar um TypeName:

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

Você ainda está obtendo apenas um único objeto, então você deve fazer um New-Contact função para garantir que todos os objetos sejam iguais, mas agora você pode facilmente verificar se um parâmetro "é" desse tipo decorando um parâmetro com o PSTypeName atributo:

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

No PowerShell 5

No PowerShell 5 tudo muda e finalmente conseguimos class e enum como palavras-chave de linguagem para definir tipos (não há struct mas tudo bem):

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

Também ganhamos uma nova maneira de criar objetos sem usar New-Object: [Contact]::new() -- na verdade, se você manteve sua classe simples e não definiu um construtor, você pode criar objetos lançando uma hashtable (embora sem um construtor, não haveria como impor que todas as propriedades devem ser definidas):

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 é o método de atalho:

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

A resposta de Steven Murawski é ótima, mas eu gosto do mais curto (ou melhor, apenas do objeto de seleção mais limpo em vez de usar a sintaxe add-member):

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
}

Surpreso, ninguém mencionou esta opção simples (vs 3 ou posterior) para criar objetos personalizados:

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

O tipo será PSCustomObject, mas não um tipo personalizado real.Mas é provavelmente a maneira mais fácil de criar um objeto personalizado.

Existe o conceito de PSObject e Add-Member que você pode usar.

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

Isso resulta como:

[8] » $contact

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

A outra alternativa (que eu saiba) é definir um tipo em C#/VB.NET e carregar esse assembly no PowerShell para uso direto.

Esse comportamento é definitivamente incentivado porque permite que outros scripts ou seções do seu script funcionem com um objeto real.

Aqui está o caminho difícil para criar tipos personalizados e armazená-los em uma coleção.

$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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top