O que é o Windows PowerShell e o que ele come? Parte 4: Trabalhando com Objetos, Classes Customizadas



A saída de texto dos comandos na janela do interpretador do PowerShell é apenas uma maneira de exibir informações em um formato legível por humanos. De fato, o ambiente está focado no trabalho com objetos: cmdlets e funções os recebem na entrada e retornam na saída , e os tipos de variáveis ​​disponíveis no modo interativo e nos scripts são baseados nas classes .NET. No quarto artigo do ciclo, estudaremos o trabalho com objetos em mais detalhes.

Índice:


PowerShell




ForEach-Object, Group-Object Measure-Object
.NET COM (New-Object)

PSCustomObject


PowerShell


Lembre-se de que um objeto é uma coleção de campos de dados (propriedades, eventos etc.) e seus métodos de processamento (métodos). Sua estrutura é determinada pelo tipo, que geralmente é baseado nas classes usadas na plataforma .NET Core unificada. Também é possível trabalhar com objetos COM, CIM (WMI) e ADSI. São necessárias propriedades e métodos para executar várias ações nos dados; além do PowerShell, os objetos podem ser passados ​​como argumentos para funções e cmdlets, atribuídos seus valores às variáveis ​​e também há um mecanismo para compor comandos (pipeline ou pipeline). Cada comando no pipeline passa sua saída para o próximo por turno - objeto por objeto. Para processamento, você pode usar cmdlets compilados ou criar suas próprias funções avançadasrealizar várias manipulações com objetos no pipeline: filtrar, classificar, agrupar e até alterar sua estrutura. A transferência de dados neste formulário tem uma séria vantagem: a equipe receptora não precisa analisar o fluxo de bytes (texto), todas as informações necessárias são facilmente extraídas consultando as propriedades e métodos correspondentes.

Ver estrutura do objeto


Por exemplo, execute o cmdlet Get-Process, que permite obter informações sobre os processos em execução no sistema:



Ele exibe alguns dados de texto formatados que não dão uma idéia das propriedades dos objetos retornados e seus métodos. Para ajustar a saída, você precisa aprender a examinar a estrutura dos objetos, e o cmdlet Get-Member nos ajudará com isso:

Get-Process | Get-Member



Aqui já vemos o tipo e a estrutura e, com a ajuda de parâmetros adicionais, podemos, por exemplo, exibir apenas as propriedades do objeto que entrou na entrada:

Get-Process | Get-Member -MemberType Property

Esse conhecimento será necessário para resolver tarefas administrativas de maneira interativa ou para escrever seus próprios scripts: por exemplo, para obter informações sobre processos interrompidos pela propriedade Responding.

Filtragem de Objetos


O PowerShell permite canalizar objetos que atendem a uma condição específica:

Where-Object {   }

O resultado da execução do bloco de scripts entre colchetes do operador deve ser um valor lógico. Se for verdadeiro ($ true), o objeto que inseriu o cmdlet Where-Object será transmitido pelo pipeline, caso contrário (o valor $ false) será excluído. Por exemplo, listamos os serviços interrompidos do Windows Server, ou seja, aqueles com a propriedade Status definida como Parado:

Get-Service | Where-Object {$_.Status -eq "Stopped"}



Aqui vemos novamente a representação textual, mas se você deseja entender o tipo e a estrutura interna dos objetos que passam pelo pipeline, é fácil:

Get-Service | Where-Object {$_.Status -eq "Stopped"} | Get-Member



Classificar objetos


Ao canalizar objetos, geralmente é necessário classificá-los. Os nomes de propriedades (chaves de classificação) são passados ​​para o cmdlet Sort-Object e retornam objetos ordenados por seus valores. A saída dos processos em execução pode ser facilmente classificada pelo tempo gasto do processador (propriedade da CPU):

Get-Process | Sort-Object –Property cpu

O parâmetro -Property pode ser omitido ao chamar o cmdlet Sort-Object - ele é usado por padrão. Para classificação inversa, use o parâmetro -Descending:

Get-Process | Sort-Object cpu -Descending



Seleção de objetos e suas partes


O cmdlet Select-Object permite selecionar um número específico de objetos no início ou no final de um pipeline usando os parâmetros -First ou -Last. Com ele, você pode selecionar objetos únicos ou determinadas propriedades, bem como criar novos objetos com base em tais itens. Vamos ver o trabalho do cmdlet usando exemplos simples.

O comando a seguir exibe informações sobre 10 processos que consomem a quantidade máxima de RAM (propriedade WS):

Get-Process | Sort-Object WS -Descending | Select-Object -First 10



Você pode selecionar apenas determinadas propriedades dos objetos que passam pelo pipeline e criar novas com base em:

Get-Process | Select-Object ProcessName, Id -First 1

Como resultado do pipeline, obteremos um novo objeto, cuja estrutura será diferente da estrutura retornada pelo cmdlet Get-Process. Verificaremos isso usando Get-Member:

Get-Process | Select-Object ProcessName, Id -First 1 | Get-Member



Observe que Select-Object retorna um único objeto (-First 1), que possui apenas dois campos especificados por nós: seus valores foram copiados do primeiro objeto passado para o pipeline com o cmdlet Get-Process. Usando Select-Object, uma das maneiras de criar objetos nos scripts do PowerShell é baseada:

$obj = Get-Process | Select-Object ProcessName, Id -First 1
$obj.GetType()



Usando Select-Object, você pode adicionar propriedades calculadas a objetos que devem ser representados como uma tabela de hash . Nesse caso, o valor de sua primeira chave corresponde ao nome da propriedade e o valor da segunda corresponde ao valor da propriedade para o elemento atual do pipeline:

Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}}



Vejamos a estrutura dos objetos que passam pelo pipeline:

Get-Process | Select-Object -Property ProcessName, @{Name="StartTime"; Expression = {$_.StartTime.Minute}} | Get-Member



ForEach-Object, Group-Object e Measure-Object


Existem outros cmdlets para trabalhar com objetos. Por exemplo, falaremos sobre os três mais úteis:

ForEach-Object permite executar o código do PowerShell para cada objeto no pipeline:

ForEach-Object {   }

Objeto de grupo agrupa objetos por valor da propriedade:

Group-Object PropertyName

Se você executá-lo com o parâmetro -NoElement, poderá descobrir o número de elementos nos grupos.

O Measure-Object agrega vários parâmetros de resumo pelos valores dos campos dos objetos no pipeline (calcula a soma e também encontra o valor mínimo, máximo ou médio):

Measure-Object -Property PropertyName -Minimum -Maximum -Average -Sum

Normalmente, os cmdlets considerados são usados ​​interativamente e os scripts geralmente criam funções com os blocos Begin, Process e End.

Criando objetos .NET e COM (novo objeto)


Existem muitos componentes de software com interfaces .NET Core e COM que são úteis para administradores de sistema. Usando a classe System.Diagnostics.EventLog, você pode gerenciar os logs do sistema diretamente do Windows PowerShell. Vejamos um exemplo de criação de uma instância dessa classe usando o cmdlet New-Object com o parâmetro -TypeName:

New-Object -TypeName System.Diagnostics.EventLog



Como não especificamos um log de eventos específico, a instância resultante da classe não contém dados. Para alterar isso, durante sua criação, você deve chamar o método construtor especial usando o parâmetro -ArgumentList. Se quisermos acessar o log do aplicativo, passe a string "Application" como argumento para o construtor:

$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
$AppLog



Observe: salvamos a saída do comando na variável $ AppLog. Embora os pipelines sejam comumente usados ​​no modo interativo, os scripts geralmente exigem a manutenção de uma referência a objeto. Além disso, as principais classes do .NET Core estão contidas no espaço para nome do sistema: o PowerShell pesquisa por padrão os tipos especificados nele, portanto, escrever Diagnostics.EventLog em vez de System.Diagnostics.EventLog está bastante correto.

Para trabalhar com o diário, você pode consultar os métodos apropriados:

$AppLog | Get-Member -MemberType Method



Digamos que seja limpo usando o método Clear () com direitos de acesso:

$AppLog.Clear()

O cmdlet New-Object também é usado para trabalhar com componentes COM. Existem muitos deles - das bibliotecas fornecidas com o servidor de script do Windows aos aplicativos ActiveX, como, por exemplo, o Internet Explorer. Para criar um objeto COM, você precisa especificar o parâmetro -ComObject com o identificador de programa ProgId da classe desejada:

New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObject

Para criar seus próprios objetos com uma estrutura arbitrária, o uso de Novo Objeto parece muito arcaico e complicado; esse cmdlet é usado para trabalhar com componentes de software externos ao PowerShell. Nos artigos subseqüentes, esse problema será discutido em mais detalhes. Além dos objetos .NET e COM, também aprenderemos sobre objetos CIM (WMI) e ADSI.

Chamando métodos estáticos


Não é possível criar instâncias de algumas classes do .NET Core: elas incluem System.Environment e System.Math. Eles são estáticos e contêm apenas propriedades e métodos estáticos. Em essência, são bibliotecas de referência usadas sem criar objetos. Você pode se referir a uma classe estática por meio de um literal, colocando o nome do tipo entre colchetes. Além disso, se você observar a estrutura do objeto usando Get-Member, veremos o tipo System.RuntimeType em vez de System.Environment:

[System.Environment] | Get-Member



Para visualizar apenas elementos estáticos, é necessário chamar Get-Member com o parâmetro -Static (preste atenção ao tipo de objeto):

[System.Environment] | Get-Member -Static



Para acessar propriedades e métodos estáticos, dois pontos consecutivos são usados ​​em vez de um ponto após um literal:

[System.Environment]::OSVersion

Ou

$test=[System.Math]::Sqrt(25) 
$test
$test.GetType()



Tipo PSCustomObject


Entre os muitos tipos de dados disponíveis no PowerShell, vale mencionar o PSCustomObject, projetado para armazenar objetos com uma estrutura arbitrária. A criação de um objeto desse tipo usando o cmdlet New-Object é considerada uma maneira clássica, mas complicada e obsoleta:

$object = New-Object  –TypeName PSCustomObject -Property @{Name = 'Ivan Danko'; 
                                          City = 'Moscow';
                                          Country = 'Russia'}

Vejamos a estrutura do objeto:

$object | Get-Member



A partir do PowerShell 3.0, outra sintaxe está disponível:

$object = [PSCustomObject]@{Name = 'Ivan Danko'; 
                                          City = 'Moscow';
                                          Country = 'Russia'
}

Você pode acessar os dados de uma das maneiras equivalentes:

$object.Name

$object.'Name'

$value = 'Name'
$object.$value

Aqui está um exemplo de conversão de uma tabela de hash existente em um objeto:

$hash = @{'Name'='Ivan Danko'; 'City'='Moscow'; 'Country'='Russia'}
$hash.GetType()
$object = [pscustomobject]$hash
$object.GetType()



Uma das desvantagens de objetos desse tipo é que a ordem de suas propriedades pode mudar. Para evitar isso, você deve usar o atributo [ordenado]:

$object = [PSCustomObject][ordered]@{Name = 'Ivan Danko'; 
                                          City = 'Moscow';
                                          Country = 'Russia'
}

Existem outras opções para criar um objeto: acima, examinamos o uso do cmdlet Select-Object . Resta lidar com a adição e remoção de elementos. Fazer isso para o objeto do exemplo anterior é bastante simples:

$object | Add-Member –MemberType NoteProperty –Name Age  –Value 33
$object | Get-Member



O cmdlet Add-Member permite adicionar não apenas propriedades, mas também métodos ao objeto $ object criado anteriormente usando a construção "-MemberType ScriptMethod":

$ScriptBlock = {
    #  
}
$object | Add-Member -Name "MyMethod" -MemberType ScriptMethod -Value $ScriptBlock
$object | Get-Member

Nota: para armazenar o código para o novo método, usamos a variável $ ScriptBlock do tipo ScriptBlock.



Para remover propriedades, use o método apropriado:

$object.psobject.properties.remove('Name')

Criando suas próprias classes


O PowerShell 5.0 apresenta a capacidade de definir classes usando a sintaxe da característica para linguagens de programação orientadas a objetos. A palavra de serviço Class destina-se a isso, após o qual você deve especificar o nome da classe e descrever seu corpo entre colchetes do operador:

class MyClass
{
    #  
}

Esse é um verdadeiro tipo de .NET Core, cujo corpo descreve suas propriedades, métodos e outros elementos. Considere um exemplo de uma definição de classe simples:

class MyClass 
{
     [string]$Name
     [string]$City
     [string]$Country
}

Para criar um objeto (uma instância de uma classe), use o cmdlet New-Object ou um literal do tipo [MyClass] e o novo método pseudo - estático (construtor padrão):

$object = New-Object -TypeName MyClass

ou

$object = [MyClass]::new()

Vamos analisar a estrutura do objeto:

$object | Get-Member



Não se esqueça do escopo: você não pode se referir ao nome do tipo como uma sequência ou usar um literal de tipo fora do script ou módulo no qual a classe está definida. Ao mesmo tempo, as funções podem retornar instâncias da classe (objetos) que estarão disponíveis fora do módulo ou script.

Após criar o objeto, preencha suas propriedades:

$object.Name = 'Ivan Danko'
$object.City = 'Moscow'
$object.Country = 'Russia'
$object



Observe que na descrição da classe não apenas os tipos de propriedade são definidos, mas também seus valores padrão:

class Example
{
     [string]$Name = 'John Doe'
}

A descrição do método de classe se assemelha à descrição de uma função, mas sem usar a função word da função. Como na função, os parâmetros são passados ​​para os métodos, se necessário:

class MyClass 
{
     [string]$Name
     [string]$City
     [string]$Country
     
     # 
     Smile([bool]$param1)
     {
         If($param1) {
            Write-Host ':)'
         }
     }
}

Agora, o representante da nossa turma sabe sorrir:

$object = [MyClass]::new()
$object.Smile($true)

Os métodos podem ser sobrecarregados; além disso, a classe possui propriedades e métodos estáticos , além de construtores cujos nomes coincidem com o nome da própria classe. Uma classe definida em um script ou módulo do PowerShell pode servir como base para outra - é assim que a herança é implementada. Ao mesmo tempo, o uso de classes .NET existentes é permitido como base:

class MyClass2 : MyClass
{
      #  ,     MyClass
}
[MyClass2]::new().Smile($true)

Nossa descrição do trabalho com objetos no PowerShell não é exaustiva. Nas publicações a seguir, tentaremos aprofundá-lo com exemplos práticos: o quinto artigo da série será dedicado aos problemas de integração do PowerShell com componentes de software de terceiros. Partes anteriores podem ser encontradas nos links abaixo.



1: Windows PowerShell
2: Windows PowerShell
3: ,


All Articles