Tudo o que você queria saber sobre PSCustomObject

author
8 minutes, 25 seconds Read
  • 10/05/2020
  • 8 minutos para ler
    • j
    • m
    • s
    • j
    • c

PSCustomObjects são uma óptima ferramenta para adicionar à sua correia de ferramentas PowerShell. Vamos começar com o básico e trabalhar com as características mais avançadas. A ideia por trás de usar um PSCustomObject é ter uma forma simples de criar dados estruturados. Dê uma olhada no primeiro exemplo e você terá uma idéia do que isso significa.

Nota

A versão original deste artigo apareceu no blog escrito por @KevinMarquette. A equipa ThePowerShell agradece ao Kevin por partilhar este conteúdo connosco. Por favor confira seu blog emPowerShellExplained.com.

Criando um PSCustomObject

Eu adoro usar no PowerShell. Criar um objecto utilizável nunca foi tão fácil. Por causa disso, vou saltar todas as outras formas de criar um objecto mas preciso de mencionar que a maioria destes exemplos são PowerShell v3.0 e mais recentes.

$myObject = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}

Este método funciona bem para mim porque uso hashtables para quase tudo. Mas há momentos em que eu gostaria que o PowerShell tratasse os hashtables mais como um objeto. O primeiro lugar que você percebe a diferença é quando você quer usar Format-Table ou Export-CSV e você percebe que ahashtable é apenas uma coleção de pares chave/valor.

Você pode então acessar e usar os valores como você usaria um objeto normal.

$myObject.Name

Convertendo uma hashtable

Embora eu esteja no tópico, você sabia que poderia fazer isso:

$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = $myHashtable

Eu prefiro criar o objeto desde o início mas há momentos em que você tem que trabalhar com ahashtable primeiro. Este exemplo funciona porque o construtor toma uma hashtable para as propriedades do objeto. Uma nota importante é que enquanto este método funciona, ele não é um equivalente exato. A maior diferença é que a ordem das propriedades não é preservada.

Apropósito de legado

Você pode ter visto pessoas usando New-Object para criar objetos personalizados.

$myHashtable = @{ Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}$myObject = New-Object -TypeName PSObject -Property $myHashtable

Esta forma é um pouco mais lenta mas pode ser a sua melhor opção nas primeiras versões do PowerShell.

Guardar num ficheiro

Eu encontro a melhor forma de guardar um hashtable num ficheiro é guardá-lo como JSON. Você pode importá-lo de volta paraa

$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path$myObject = Get-Content -Path $Path | ConvertFrom-Json

I cobre mais maneiras de salvar objetos em um arquivo no meu artigo emThe many ways to read and write to files.

Trabalhar com propriedades

Adicionar propriedades

Você ainda pode adicionar novas propriedades ao seu PSCustomObject com Add-Member.

$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'$myObject.ID

Remover propriedades

Você também pode remover propriedades de um objeto.

$myObject.psobject.properties.remove('ID')

O psobject é uma propriedade oculta que lhe dá acesso aos metadados do objecto base.

Enumerar nomes de propriedades

Por vezes é necessária uma lista de todos os nomes de propriedades de um objecto.

$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name

Nós podemos obter esta mesma lista de psobject propriedade também.

$myobject.psobject.properties.name

Acesso cinâmico às propriedades

Eu já mencionei que você pode acessar os valores das propriedades diretamente.

$myObject.Name

Pode usar uma string para o nome da propriedade e ainda funcionará.

$myObject.'Name'

Podemos dar mais um passo e usar uma variável para o nome da propriedade.

$property = 'Name'$myObject.$property

Eu sei que parece estranho, mas funciona.

Converta PSCustomObject num hashtable

Para continuar a partir da última secção, pode caminhar dinamicamente pelas propriedades e criar um hashtable a partir delas.

$hashtable = @{}foreach( $property in $myobject.psobject.properties.name ){ $hashtable = $myObject.$property}

Teste para propriedades

Se você precisa saber se uma propriedade existe, você poderia apenas verificar se essa propriedade tem um valor.

if( $null -ne $myObject.ID )

Mas se o valor puder ser $null você pode verificar se ele existe verificando apsobject.properties para ele.

if( $myobject.psobject.properties.match('ID').Count )

Adicionando métodos de objetos

Se você precisar adicionar um método de script a um objeto, você pode fazê-lo com Add-Member e aScriptBlock. Você tem que usar a variável automática this para referenciar o objeto atual. Aqui está umascriptblock para transformar um objeto em um hashtable. (mesmo código do último exemplo)

Então adicionamo-lo ao nosso objecto como propriedade do script.

Então podemos chamar a nossa função assim:

$myObject.ToHashtable()

Objectos vs Tipos de valores

Objectos e tipos de valores não lidam com atribuições de variáveis da mesma forma. Se você atribuir tipos de valores a outros, apenas o valor é copiado para a nova variável.

$first = 1$second = $first$second = 2

Neste caso, $first é 1 e $second é 2.

Variáveis de objeto têm uma referência para o objeto real. Quando você atribui um objeto a uma nova variável, elas ainda referenciam o mesmo objeto.

$third = @{Key=3}$fourth = $third$fourth.Key = 4

Porque $third e $fourth referenciam a mesma instância de um objeto, ambas $third.key e $fourth.Key são 4.

psobject.copy()

Se você precisar de uma cópia verdadeira de um objeto, você pode cloná-lo.

$third = @{Key=3}$fourth = $third.psobject.copy()$fourth.Key = 4

Clone cria uma cópia rasa do objeto. Eles têm instâncias diferentes agora e $third.key é 3e $fourth.Key é 4 neste exemplo.

Eu chamo isto de uma cópia rasa porque se você tem objetos aninhados. (onde as propriedades contêm outros objetos). Apenas os valores de nível superior são copiados. Os objetos filhos se referenciarão uns aos outros.

PSTypeName para tipos de objetos personalizados

Agora que temos um objeto, há mais algumas coisas que podemos fazer com ele que podem não ser quase inócuas. A primeira coisa que precisamos fazer é dar-lhe um . Esta é a forma mais comum que vejo as pessoas fazerem isso:

$myObject.PSObject.TypeNames.Insert(0,"My.Object")

Recentemente descobri outra forma de fazer isso a partir deste post por /u/markekraus. Eu fiz um pequeno e mais posts sobre a idéia de Adam Bertram e Mike Shepard onde eles falam sobre essa abordagem que permite que você a defina em linha.

$myObject = @{ PSTypeName = 'My.Object' Name = 'Kevin' Language = 'PowerShell' State = 'Texas'}

Eu adoro como isso se encaixa bem na linguagem. Agora que temos um objeto com um nome de digitação apropriado, podemos fazer mais algumas coisas.

Note

Você também pode criar tipos personalizados de PowerShell usando classes PowerShell. Para mais informações, vejaPowerShell Class Overview.

Using DefaultPropertySet (the long way)

PowerShell decide para nós quais propriedades exibir por padrão. Muitos dos comandos nativos têm um arquivo de formatação.ps1xml que faz todo o trabalho pesado. A partir deste post do Boe Prox, há outra forma de fazermos isto no nosso objecto personalizado usando apenas o PowerShell. Podemos dar-lhe umMemberSet para ele usar.

Agora quando o meu objecto apenas cair na shell, ele apenas mostrará essas propriedades por defeito.

Update-TypeData with DefaultPropertySet

Isso é bom mas recentemente vi uma forma melhor quando vi o PowerShell desligado em 2016 com Jeffrey Snover & Don Jones. Jeffrey estava usandoUpdate-TypeData para especificar as propriedades padrão.

$TypeData = @{ TypeName = 'My.Object' DefaultDisplayPropertySet = 'Name','Language'}Update-TypeData @TypeData

Isso é simples o suficiente para que eu quase me lembrasse disso se eu não tivesse esse post como referência rápida. Agora eu posso facilmente criar objetos com muitas propriedades e ainda dar-lhe uma boa visão limpa quando olho para ele a partir do shell. Se eu precisar acessar ou ver essas outras propriedades, elas permanecem lá.

$myObject | Format-List *

Update-TypeData com ScriptProperty

Algo mais que eu tirei daquele vídeo foi criar propriedades de script para seus objetos. Este seria um bom momento para apontar que isto também funciona para objetos existentes.

Você pode fazer isto antes do seu objeto ser criado ou depois e ele ainda vai funcionar. Isto é o que torna isto diferente de usar Add-Member com uma propriedade script. Quando você usa Add-Member da maneira que o Ireferenced anteriormente, ele só existe naquela instância específica do objeto. Este aplica-se a allobjects com isto TypeName.

Function parameters

You pode agora usar estes tipos personalizados para parâmetros nas suas funções e scripts. Você pode ter onefunction criar esses objetos personalizados e depois passá-los para outras funções.

param( $Data )

PowerShell requer que o objeto seja o tipo especificado por você. Ele lança um erro de validação se o tipo não corresponder automaticamente para salvar o passo de teste para ele no seu código. Um greatexample de deixar o PowerShell fazer o que ele faz melhor.

Function OutputType

Você também pode definir um OutputType para suas funções avançadas.

function Get-MyObject{ param ( ...

O valor do atributo OutputType é apenas uma nota de documentação. Ele não é derivado do código da função ou comparado com a saída real da função.

A principal razão pela qual você usaria um tipo de saída é para que a meta informação sobre sua função reflita suas intenções. Coisas como Get-Command e Get-Help que o seu ambiente de desenvolvimento pode tirar proveito. Se você quiser mais informações, então dê uma olhada na ajuda para isso:about_Functions_OutputTypeAttribute.

Posto isso, se você estiver usando Pester para testar suas funções por unidade, então seria uma boa idéia validar os objetos de saída correspondentes ao seu OutputType. Isto poderia pegar variáveis que caem no pipe quando elas não deveriam.

Closing thoughts

O contexto disto tudo era sobre , mas muitas destas informações se aplicam aos objetos em geral.

Eu já vi a maioria destas características de passagem, mas nunca as vi apresentadas como uma coleção de informações em PSCustomObject. Ainda na semana passada tropeçei em outra e fiquei surpreso por não tê-la visto antes. Eu queria juntar todas essas idéias para que você possa ter uma visão mais ampla e estar ciente delas quando tiver a oportunidade de usá-las. Espero que você tenha aprendido alguma coisa e possa encontrar uma maneira de trabalhar isso em seus roteiros.

Similar Posts

Deixe uma resposta

O seu endereço de email não será publicado.