- 10/05/2020
- 8 minutos para ler
-
- j
- m
- s
- j
- c
PSCustomObject
s 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
- Convertendo uma hashtable
- Apropósito de legado
- Guardar num ficheiro
- Trabalhar com propriedades
- Adicionar propriedades
- Remover propriedades
- Enumerar nomes de propriedades
- Acesso cinâmico às propriedades
- Converta PSCustomObject num hashtable
- Teste para propriedades
- Adicionando métodos de objetos
- Objectos vs Tipos de valores
- psobject.copy()
- PSTypeName para tipos de objetos personalizados
- Using DefaultPropertySet (the long way)
- Update-TypeData with DefaultPropertySet
- Update-TypeData com ScriptProperty
- Function parameters
- Function OutputType
- Closing thoughts
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.