Classes do PowerShell: Começando

PowerShell é uma linguagem orientada a objetos. Ao executar comandos, você vê a saída na tela; esses são objetos. Objetos não surgem do nada; os desenvolvedores os criam ou, mais especificamente, os instanciam com classes. As classes do PowerShell representam definições ou esquemas desses objetos.

Embora você possa estar familiarizado com a criação de objetos usando comandos como New-Object e o uso do acelerador de tipo pscustomobject, esses não são objetos “novos”. Os tipos de objetos que esses métodos produzem são de um tipo específico. As classes do PowerShell definem o tipo.

Neste tutorial, você aprenderá como começar com classes no PowerShell. Você criará sua primeira classe com construtores, aprenderá a criar objetos a partir de sua classe e personalizará sua classe com propriedades e métodos.

Para informações sobre termos como objetos, propriedades e métodos, confira a postagem no blog De Volta às Origens: Entendendo Objetos no PowerShell.

Pré-requisitos

Criando Sua Primeira Classe e Objeto

Antes de mergulhar nos detalhes de uma classe no PowerShell, é recomendável criar uma classe simples. Tópicos mais avançados serão abordados mais tarde.

Criar sua primeira classe vai parecer um pouco com criar uma função. A sintaxe básica é a mesma. Uma classe é criada a partir de uma definição, assim como uma função. No entanto, ao contrário das funções, a primeira linha não começa com function seguido pelo nome da função, mas sim com class seguido pelo nome do seu tipo de objeto.

Abaixo, você verá o esqueleto básico de uma classe chamada aluno.

class student {

}

Classes têm propriedades que se parecem com parâmetros, são atributos que descrevem essa classe. O exemplo abaixo mostra uma classe chamada aluno com duas propriedades; Nome e Sobrenome.

Ao definir uma propriedade, você deve sempre definir um tipo que estabeleça um “esquema” específico para o que os valores da propriedade podem conter. No exemplo abaixo, ambas as propriedades são definidas como strings.

Você sempre deve definir tipos de propriedade. Você verá o motivo depois.

class student {
    [string]$FirstName
    [string]$LastName
}

Depois de definir uma classe, crie um objeto a partir dela ou instancie um objeto. Existem várias maneiras de instanciar objetos a partir de classes; uma maneira comum é usar aceleradores de tipo, como [aluno], que representam a classe, seguido por um método padrão que vem com toda classe chamado new().

Usar o atalho do acelerador de tipo é o mesmo que criar um objeto usando o comando New-Object.

New-Object -TypeName student

Uma vez que você tenha criado um objeto a partir dessa classe, atribua valores às propriedades. O exemplo abaixo está atribuindo os valores de Tyler e Muir para as propriedades FirstName e LastName.

class student {
    [string]$FirstName
    [string]$LastName
}
$student1 = [student]::new()
$student1.FirstName = 'Tyler'
$student1.LastName = 'Muir'
$student1

Depois de criar o objeto e atribuir valores às propriedades, inspecione o objeto chamando a variável à qual você atribuiu o objeto, como mostrado abaixo.

Creating an object from the student class.

Agora que você criou um objeto a partir de uma classe, encaminhe esse objeto da mesma forma que qualquer outro objeto no PowerShell para o cmdlet Get-Member para inspecioná-lo. Você pode ver abaixo que o objeto contido na variável $student1 é do tipo student.

O nome da classe sempre se correlacionará com o tipo de objeto.

Observe que o Get-Member retorna quatro métodos e duas propriedades. As propriedades provavelmente parecem familiares, mas os métodos certamente não. O PowerShell adiciona certos métodos por padrão, mas você pode adicionar seus próprios métodos ou até mesmo modificar os métodos padrão.

Showing members from custom student object.

Criando Métodos

No exemplo acima, você viu alguns métodos padrão no objeto, mas é provável que você queira criar os seus próprios. Para fazer isso, é necessário definir um ou mais métodos dentro da definição da classe.

A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.

[<output type>]<name>() {
	<code that runs when the method is executed>
}

Observe os parênteses () após o nome. Aqui é onde você pode definir os parâmetros do método (explicados posteriormente). Os parâmetros do método permitem que você altere a funcionalidade de um método da mesma forma que pode fazer com parâmetros de função.

Se você já escreveu e executou funções PowerShell antes, os scriptblocks de método devem parecer familiares, mas há algumas regras especiais para métodos que você deve conhecer.

O uso do return é obrigatório em funções PowerShell, que retornarão objetos simplesmente colocando o objeto em qualquer lugar da função, como no exemplo abaixo.

“`powershell
## Apenas enviando o objeto para o pipeline
“`

No entanto, ao contrário das funções, se um método retorna um objeto, você deve usar a construção return, como mostrado abaixo.

Usando a variável $this, outra diferença que os métodos têm em relação às funções é a variável $this. A variável $this, definida dentro de um método, faz referência às propriedades ou outros métodos do objeto atual.

Aqui está um exemplo de um método chamado GetName() adicionado à classe student que concatena o valor das propriedades FirstName e LastName e os retorna.

Agora você pode chamar o método GetName() usando a notação de ponto como mostrado abaixo. Se você atribuiu valores anteriormente a FirstName e LastName, GetName() os retornará.

Adicionando Parâmetros aos Métodos

No exemplo acima, quando você executou a linha $student1.GetName(), você estava chamando o método GetName() como está. Dentro dos parênteses, você pode definir parâmetros da mesma forma que as funções.“`Portuguese
Se você já escreveu e executou funções no PowerShell antes, o método scriptblocks deve parecer familiar, mas há algumas regras especiais para métodos que você deve conhecer.

return é obrigatório

As funções do PowerShell retornarão objetos simplesmente colocando o objeto em qualquer lugar da função, como no exemplo abaixo.

function foo {
	$object = Get-Service
	$object ## Apenas enviando o objeto para o pipeline
}

No entanto, ao contrário das funções, se um método retornar um objeto, você deve usar a construção return conforme mostrado abaixo.

[string]GetName() {
	return 'foo'
}

Usando a variável $this

Outra diferença que os métodos têm em relação às funções é a variável $this. A variável $this, conforme definida dentro de um método, faz referência às propriedades ou outros métodos do objeto atual.

Abaixo está um exemplo de um método chamado GetName() adicionado à classe student que concatena o valor das propriedades FirstName e LastName e os retorna.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
}

Agora você pode chamar o método GetName() usando a notação de ponto, como mostrado abaixo. Se você atribuiu valores anteriormente a FirstName e LastName, GetName() os retornará.

Creating a class with a method and showing to output.

Adicionando Parâmetros a Métodos

No exemplo acima, quando você executou a linha $student1.GetName(), você estava chamando o método GetName() como está. Dentro dos parênteses, você pode definir parâmetros da mesma forma que em funções.

O método GetName() apenas devolvia os valores definidos para as propriedades FirstName e LastName. Mas e se você preferir ter um método para definir as propriedades que o GetName() pode então obter? Nesse caso, você precisa definir parâmetros do método.

Defina os parâmetros do método incluindo um ou mais parâmetros separados por vírgulas entre os parênteses dos parâmetros do método, como mostrado abaixo.

Observe o tipo de saída [void]. Sempre que um método não produzir nada, você não precisa de uma construção return, e você deve definir o tipo de saída como [void] para informar ao PowerShell que o método não retorna nada.

[void]SetName([string]$Name) {

}

Por exemplo, talvez o método SetName() aceite um nome completo (nome e sobrenome). Se for o caso, no bloco de script, você pode então dividir essa string e atribuir o nome e sobrenome dessa maneira.

Ao inserir o método SetName() na classe student, abaixo está como ele fica agora.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

Agora você pode passar um nome completo como parâmetro para o método SetName(), que define as propriedades FirstName e LastName do objeto atual.

Creating a class with a void method and showing the output when it is run.

Sobrecarga de Métodos

Talvez você queira definir diferentes conjuntos de parâmetros para um método. Semelhante a como os conjuntos de parâmetros funcionam em funções e cmdlets, você pode definir diferentes “contextos” de parâmetros ou assinaturas de método.

Talvez você queira configurar os parâmetros FirstName e LastName passando um nome completo para o método SetName() ou passando o primeiro e o último nome separadamente. Você não precisa escolher; você pode defini-los ambos com as assinaturas do método.

Ao definir mais de uma assinatura de método em uma classe, isso é chamado de sobrecarga.

Reutilizando o exemplo da seção anterior, você pode criar uma sobrecarga para o método SetName() para aceitar duas strings em vez de uma. Quando você passa duas strings em vez de uma, o método SetName() assume que a primeira string é o FirstName e a segunda string é o LastName. Com essa sobrecarga, a classe ficaria assim abaixo.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
    
    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}
Showing that the method overload works by providing either one or two strings.

Construtores de Classe

Sempre que você instanciar um objeto com o método new() ou de outra forma, você pode dizer ao PowerShell para executar algum código definido pelo usuário chamado construtor. Construtores são como métodos, mas são executados automaticamente quando o PowerShell instancia um objeto.

Toda classe tem um construtor padrão. Este construtor padrão não faz muito; ele apenas instancia o objeto. Você pode ver o construtor padrão visualizando a saída do método New. Você pode ver abaixo que esta linha retorna um único método new().

[student]::New
Default PowerShell constructor

Sobrecarga de Construtor

Talvez queira definir um valor para as propriedades FirstName e LastName assim que criar o objeto, não usando a notação típica de ponto. Nesse caso, pode criar um construtor com um parâmetro que, em seguida, chama SetName().

Abaixo está um exemplo de um construtor para a classe student. Observe que o construtor não tem um nome específico ou é precedido por um tipo de saída. Construtores sempre usam o mesmo nome que a classe.

Chamar um método existente no construtor nos permite reutilizar o método que já escrevemos para lidar com a configuração das variáveis.

student([string]$Name) {
	$this.SetName($Name)
}

E abaixo você verá esse construtor adicionado à classe student.

class student {
    [string]$FirstName
    [string]$LastName
    
    student([string]$Name) {
        $this.SetName($Name)
    }

    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

Ao instanciar um novo objeto student e passar um parâmetro de string, as propriedades do objeto terão imediatamente os valores esperados.

Showing the output from using the constructor with a string

Agora você pode ver novamente o construtor sobrecarregado com [student]::New. Observe agora que o novo construtor sobrecarregado é definido com um parâmetro Name.

Overloaded constructor

Definindo um Construtor Padrão e Sobrecarregado

Agora que você tem um construtor sobrecarregado em sua classe student, o PowerShell sobrescreve o construtor padrão. Mas você pode recuperá-lo criando manualmente um sem parâmetros.

student() {}

Você pode ver como isso fica na classe student abaixo.

class student {
    [string]$FirstName
    [string]$LastName

    student([string]$Name) {
        $this.SetName($Name)
    }

    student() {}

    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

Agora verifique os construtores novamente. Agora você verá ambos os construtores aparecerem.

[student]::New
Creating a default and custom constructor

Herança de Classe

Como todas as outras linguagens orientadas a objetos, você pode construir classes no PowerShell hierarquicamente com múltiplas classes. Cada classe pode ter classes “pai” e “filho” que começam de propósitos menos específicos e mais genéricos e aumentam em especificidade.

Por exemplo, nossa classe student representa um estudante universitário (filho/específico). Esse estudante universitário é uma pessoa (pai/genérico). Esses dois conceitos estão relacionados e formam uma hierarquia.

A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person class may have properties like eye_color, height, and weight and perhaps a method called SetHeight().

Se um estudante é uma pessoa, esse estudante ainda possui aquelas propriedades e métodos. Seria duplicar esforços implementar esses mesmos membros na classe student que a classe person já possui. Você pode definir a herança de classes para definir automaticamente todos os membros da classe person na classe student.

Se isso não faz sentido agora, fará sentido à medida que avançarmos por uma demonstração.

Demonstração de Herança de Classes

Primeiro, faça uma cópia da classe student que você criou anteriormente, remova os construtores e renomeie-a para uma classe person. Sua classe person deve ficar como a classe abaixo.

A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

Agora, crie algumas classes que representem uma pessoa, mas tenham um papel mais específico. Por exemplo, no trecho de código abaixo, agora você tem uma classe teacher e uma classe student.

class teacher {
    [int]$EmployeeId
}

class student {
    [int]$StudentId
}

Como está, as classes teacher e student são mutuamente exclusivas da classe person. Elas não têm relação, mas não podem herdar nenhum membro da classe person. Vamos mudar isso.

Agora defina essa hierarquia ao definir as classes teacher e student como classes “filhas” da classe person com herança. Você pode definir a herança acrescentando dois pontos (:) após o nome da classe, seguido pelo nome da classe pai, como mostrado abaixo.

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

Agora, seu script de classe inteiro deve parecer assim:

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

Neste ponto, ao instanciar um objeto das classes teacher ou student, ambas as classes terão os mesmos membros da classe person.

Class Inheritance Demo

Herança com Construtores

Como você viu anteriormente, os métodos de classe são herdados por meio da herança de classe. Esse comportamento pode levá-lo a pensar que os construtores seguiriam a mesma lógica, mas você estaria errado. Os construtores não são herdados, e os construtores de todas as classes filhas devem ser definidos em cada classe filha separadamente.

Por exemplo, talvez você tenha acabado de definir um construtor sobrecarregado para a classe person, mas não definiu um construtor para a classe teacher, como mostrado abaixo.

class person {
    [string]hidden $FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }

		person([string]$Name) {
			$this.SetName($Name)
		}
}

Em seguida, você define uma classe filha, teacher, por exemplo, e tenta criar um objeto sem parâmetros dela, como mostrado abaixo. Observe que o PowerShell retorna um erro porque um construtor sem parâmetros não foi definido dentro da classe teacher.

No class defined for child class

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.

Atributos de Membro da Classe

Assim como os parâmetros de comando do PowerShell, as classes podem ter atributos de membro. Esses atributos modificam o comportamento de cada membro.

Membros Ocultos

Se estiver a usar um membro de classe apenas para fins internos e não deseja que o utilizador o leia ou escreva, pode definir um membro como oculto. Por exemplo, talvez tenha um método que só é usado por outros métodos. Não há necessidade de expor esse método ao utilizador.

Para definir um membro oculto, utilize o atributo hidden conforme mostrado abaixo.

class teacher {
    [int]hidden $EmployeeId
}

Agora, quando utiliza o Get-Member para inspecionar todos os membros do objeto, essa propriedade não aparece.

Class Member Attributes

A definição de um membro de classe como oculto não restringe o acesso ao valor; apenas o oculta da vista. Não deve ocultar propriedades para armazenar dados sensíveis.

Membros Estáticos

Lembre-se, anteriormente, este tutorial utilizou o termo “instanciar” para descrever a criação de um objeto a partir de uma classe. Quando instancia um objeto, esse objeto assume todas as propriedades e métodos que a classe define. Mas nem sempre é o caso.

Às vezes, não precisa da sobrecarga de instanciar um objeto inteiro. Em vez disso, precisa de referenciar rapidamente um único membro de classe. Nesse caso, pode definir um membro de classe como estático.

Assim como com o atributo hidden, defina um membro de classe como estático usando a palavra-chave static conforme mostrado abaixo.

class student {
	[int]static $MaxClassCount = 7
}

Ao contrário dos membros de classe típicos, o PowerShell não cria propriedades e métodos a partir de membros de classe estáticos. Quando define um membro de classe como estático, assim como membros ocultos, este não aparece quando utiliza o Get-Member.

Static Members

Por exemplo, talvez você queira associar nomes de disciplinas universitárias com a classe student e definir o número máximo de disciplinas universitárias que um estudante pode participar. Para fazer isso, você cria um membro de array Classes e um membro MaxClassCount.

Como o usuário raramente precisa alterar o membro MaxClassCount, você decide defini-lo como estático.

Finalmente, você cria um método AddClass() para adicionar uma disciplina ao cronograma do estudante, mas apenas se for menor que MaxClassCount.

class student {
    [string[]]$Classes = @()
    [int]static $MaxClassCount = 7
    
    [void]AddClass ([string]$Name) {
        if ($this.Classes.Count -lt [student]::MaxClassCount) {
            $this.Classes += $Name
        }
    }
}

Agora, ao tentar criar um novo objeto student e atribuir muitas disciplinas universitárias a ele, o PowerShell atribuirá apenas o número máximo, que seria sete.

$student1 = [student]::new()
'PE','English','Math','History','Computer Science','French','Wood Working','Cooking' | ForEach-Object {
	$student1.AddClass($_)
}
$student1.Classes
Class Count

Você pode alterar os valores dos membros estáticos a qualquer momento. Se, por exemplo, quiser definir o membro MaxClassCount como 5 em vez de 7, você alteraria o valor usando [student]::MaxClassCount = 5. A mudança de valor não removeria retroativamente as disciplinas que ultrapassam o limite neste exemplo.

Conclusão

As classes no PowerShell borram a linha entre uma linguagem de script e uma linguagem de programação. Classes são uma ótima maneira de definir relacionamentos entre objetos, adicionar formas de interagir e formatar objetos que normalmente só seriam possíveis escrevendo funções especializadas.

Source:
https://adamtheautomator.com/powershell-classes/