Classes em PowerShell
LidoNesta aula, você aprenderá a criar e usar classes em PowerShell, desde a sintaxe básica até construtores, propriedades e métodos, e quando faz sentido usá-las em scripts.
Bem-vindo à aula 85 do nosso curso de PowerShell! Hoje vamos explorar um dos recursos mais poderosos e, às vezes, subutilizados do PowerShell: as classes. Se você já programou em linguagens como C# ou Java, vai se sentir em casa. Se não, não se preocupe: vamos começar do básico e avançar passo a passo.
As classes no PowerShell permitem criar tipos personalizados com propriedades e métodos, encapsulando dados e comportamento. Elas foram introduzidas na versão 5.0 e são uma forma de trazer programação orientada a objetos (POO) mais formal para seus scripts. Vamos entender como usá-las, quando usá-las e por que elas podem tornar seu código mais organizado e reutilizável.
class (PS 5+)
O PowerShell 5.0 introduziu a palavra-chave class para definir classes. Antes disso, você precisava usar Add-Type com C# ou usar PSCustomObject para simular objetos. Agora, você pode definir uma classe diretamente no seu script ou módulo.
A sintaxe básica é:
class NomeDaClasse {
# propriedades e métodos
}Vamos criar um exemplo simples: uma classe para representar uma Pessoa.
class Pessoa {
[string]$Nome
[int]$Idade
}
# Criando uma instância
$pessoa = [Pessoa]::new()
$pessoa.Nome = "João"
$pessoa.Idade = 30
# Exibindo
$pessoaPerceba que usamos [Pessoa]::new() para criar uma nova instância. Isso chama o construtor padrão (sem parâmetros). Você também pode usar New-Object Pessoa.
As propriedades são definidas com tipos entre colchetes, como [string] e [int]. Se você não especificar um tipo, o PowerShell assume que é [object], mas é boa prática sempre definir tipos.
Além disso, você pode definir propriedades com valores padrão:
class Pessoa {
[string]$Nome = "Sem nome"
[int]$Idade = 0
}E também pode usar atributos como [ValidateNotNull()] ou [ValidateRange()] para validar valores.
Uma observação importante: as classes no PowerShell são reference types, ou seja, quando você atribui uma variável a outra, ambas apontam para o mesmo objeto. Isso é diferente de tipos primitivos como int ou string.
Propriedades e métodos
Propriedades armazenam dados do objeto. Em PowerShell, você pode defini-las como campos simples (como vimos) ou com getters e setters personalizados (usando hidden e lógica interna). Métodos são funções associadas à classe que podem operar nos dados.
Vamos adicionar métodos à nossa classe Pessoa:
class Pessoa {
[string]$Nome
[int]$Idade
[string]Apresentar() {
return "Olá, meu nome é $($this.Nome) e tenho $($this.Idade) anos."
}
[void]Aniversario() {
$this.Idade++
}
}
$p = [Pessoa]::new()
$p.Nome = "Maria"
$p.Idade = 25
$p.Apresentar()
$p.Aniversario()
$p.Idade # agora 26Note que usamos $this para referenciar o próprio objeto dentro dos métodos. O tipo de retorno é definido antes do nome do método, como [string] ou [void]. Se você não especificar, será [object].
Você também pode definir propriedades computadas, que são calculadas dinamicamente:
class Retangulo {
[double]$Largura
[double]$Altura
[double]Area() {
return $this.Largura * $this.Altura
}
[double]Perimetro() {
return 2 * ($this.Largura + $this.Altura)
}
}Métodos podem receber parâmetros, como qualquer função:
class Calculadora {
[int]Somar([int]$a, [int]$b) {
return $a + $b
}
}Além disso, você pode usar static para métodos que não dependem de uma instância:
class Utils {
static [string]ConverterParaMaiusculo([string]$texto) {
return $texto.ToUpper()
}
}
[Utils]::ConverterParaMaiusculo("teste")Construtores
Construtores são métodos especiais chamados quando você cria uma nova instância. Eles inicializam os valores das propriedades. Você pode definir um construtor padrão (sem parâmetros) e construtores sobrecarregados (com parâmetros diferentes).
No PowerShell, o construtor é definido com o nome NomeDaClasse(). Vamos ver:
class Pessoa {
[string]$Nome
[int]$Idade
# Construtor padrão
Pessoa() {
$this.Nome = "Desconhecido"
$this.Idade = 0
}
# Construtor com parâmetros
Pessoa([string]$nome, [int]$idade) {
$this.Nome = $nome
$this.Idade = $idade
}
}
# Uso
$p1 = [Pessoa]::new() # usa o padrão
$p2 = [Pessoa]::new("Ana", 28) # usa o com parâmetrosSe você não definir nenhum construtor, o PowerShell cria um construtor padrão implícito que inicializa as propriedades com seus valores padrão (zero, vazio, etc.).
É possível chamar um construtor a partir de outro usando this():
class Pessoa {
[string]$Nome
[int]$Idade
Pessoa() : this("Desconhecido", 0) {}
Pessoa([string]$nome, [int]$idade) {
$this.Nome = $nome
$this.Idade = $idade
}
}Isso evita duplicação de código. Outra técnica é usar inicializadores de propriedade diretamente:
class Pessoa {
[string]$Nome = "Desconhecido"
[int]$Idade = 0
Pessoa() {}
Pessoa([string]$nome, [int]$idade) {
$this.Nome = $nome
$this.Idade = $idade
}
}Quando usar
Classes são úteis quando você precisa de objetos com comportamento e estado, especialmente se você está criando módulos ou scripts complexos. Elas ajudam a organizar código, promovem reutilização e facilitam manutenção.
Aqui estão alguns cenários onde classes são recomendadas:
- Modelagem de entidades do mundo real: como clientes, produtos, pedidos, etc.
- Encapsulamento de lógica: agrupar dados e funções relacionadas.
- Herança e polimorfismo: criar hierarquias de classes para compartilhar comportamento.
- Módulos PowerShell: exportar classes para que outros usuários possam criar objetos personalizados.
Por outro lado, para scripts simples, pode ser overkill. Se você só precisa passar dados, PSCustomObject ou hashtables podem ser suficientes. Classes adicionam uma camada de complexidade que pode não ser necessária.
Um exemplo prático: criar uma classe para gerenciar um arquivo de log.
class LogManager {
[string]$Caminho
LogManager([string]$caminho) {
$this.Caminho = $caminho
}
[void]Escrever([string]$mensagem) {
$linha = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $mensagem"
Add-Content -Path $this.Caminho -Value $linha
}
[string[]]Ler() {
return Get-Content -Path $this.Caminho
}
}
$log = [LogManager]::new("C:\temp\meuapp.log")
$log.Escrever("Início")
$log.Escrever("Processando...")
$log.Ler()Isso encapsula a lógica de escrita e leitura, facilitando a reutilização em outros scripts.
Boas práticas e observações finais
- Defina sempre tipos explícitos para propriedades e métodos, pois isso melhora a clareza e a performance.
- Use
hiddenpara propriedades que não devem ser visíveis externamente, mas ainda podem ser usadas internamente. - Evite lógica complexa nos construtores; prefira métodos para inicialização adicional.
- Considere usar
enumpara valores fixos, como status. - Lembre-se de que as classes são tipadas estaticamente no PowerShell, mas você pode usar
[object]para flexibilidade.
Uma dica: quando você define uma classe em um script, ela é carregada apenas quando o script é executado. Se você usar using module, as classes podem ser importadas de módulos.
Referências
- about_Classes - PowerShell | Microsoft Learn
- about_Objects - PowerShell | Microsoft Learn
- about_Methods - PowerShell | Microsoft Learn
- about_Properties - PowerShell | Microsoft Learn
- about_Constructors - PowerShell | Microsoft Learn
- PowerShell 101: Functions - Microsoft Learn
Exercícios
- Exercício 1: Crie uma classe chamada
Carrocom propriedadesMarca,ModeloeAno. Adicione um métodoDetalhes()que retorna uma string com as informações do carro. Instancie um objeto e chame o método. - Exercício 2: Defina uma classe
ContaBancariacom propriedadesTitulareSaldo(privado). Inclua métodosDepositar()eSacar()que modifiquem o saldo. Use um construtor que inicialize o titular e o saldo inicial. - Exercício 3: Implemente uma classe
Temperaturaque armazena o valor em Celsius e tenha métodos para converter para Fahrenheit e Kelvin. Inclua um construtor que receba o valor em Celsius. - Exercício 4: Crie uma classe
Livrocom propriedadesTitulo,AutoreAnoPublicacao. Adicione um método estáticoCriarLivro()que retorna um novo livro com valores padrão. Use esse método para criar um livro. - Exercício 5: Explique quando você usaria uma classe em vez de um
PSCustomObject. Dê um exemplo de situação em que uma classe é mais adequada.
class Carro {
[string]$Marca
[string]$Modelo
[int]$Ano
[string]Detalhes() {
return "$($this.Marca) $($this.Modelo) ($($this.Ano))"
}
}
$carro = [Carro]::new()
$carro.Marca = "Toyota"
$carro.Modelo = "Corolla"
$carro.Ano = 2020
$carro.Detalhes()class ContaBancaria {
[string]$Titular
hidden [double]$Saldo
ContaBancaria([string]$titular, [double]$saldoInicial) {
$this.Titular = $titular
$this.Saldo = $saldoInicial
}
[void]Depositar([double]$valor) {
$this.Saldo += $valor
}
[bool]Sacar([double]$valor) {
if ($valor -le $this.Saldo) {
$this.Saldo -= $valor
return $true
} else {
return $false
}
}
[double]VerSaldo() {
return $this.Saldo
}
}
$conta = [ContaBancaria]::new("João", 1000)
$conta.Depositar(500)
$conta.Sacar(200)
$conta.VerSaldo()class Temperatura {
[double]$Celsius
Temperatura([double]$celsius) {
$this.Celsius = $celsius
}
[double]ParaFahrenheit() {
return ($this.Celsius * 9/5) + 32
}
[double]ParaKelvin() {
return $this.Celsius + 273.15
}
}
$temp = [Temperatura]::new(25)
$temp.ParaFahrenheit()
$temp.ParaKelvin()class Livro {
[string]$Titulo
[string]$Autor
[int]$AnoPublicacao
static [Livro]CriarLivro() {
$livro = [Livro]::new()
$livro.Titulo = "Sem título"
$livro.Autor = "Desconhecido"
$livro.AnoPublicacao = 2000
return $livro
}
}
$livro = [Livro]::CriarLivro()
$livro