Propriedades calculadas
Esta aula ensina como criar propriedades calculadas no PowerShell usando hashtables, permitindo transformar e personalizar a saída de comandos como Select-Object e Format-Table. Você aprenderá a sintaxe, casos de uso comuns e verá exemplos práticos.
Bem-vindo à aula sobre propriedades calculadas no PowerShell! Este é um recurso poderoso que permite transformar, renomear e criar novas propriedades a partir de dados existentes, sem precisar armazenar em variáveis intermediárias. Em vez de exibir apenas as propriedades nativas de um objeto, você pode calcular valores personalizados, formatar strings, aplicar lógica condicional e muito mais.
As propriedades calculadas são amplamente utilizadas em pipelines para gerar relatórios, formatar saídas de forma legível e extrair informações específicas. Dominar esse conceito eleva sua produtividade e torna seus scripts muito mais eficientes e elegantes.
Hashtable @{Name=
No PowerShell, uma propriedade calculada é definida como uma hashtable com uma ou mais chaves específicas. A chave mais comum é Name, que define o nome da nova propriedade que aparecerá na saída. A hashtable começa com @{ e contém pares chave-valor separados por ponto e vírgula ou quebras de linha.
Por exemplo, para criar uma propriedade chamada 'TamanhoKB' que calcula o tamanho de um arquivo em kilobytes, você usaria:
@{Name='TamanhoKB'; Expression={ $_.Length / 1KB }}A chave Expression é obrigatória (ou pode ser abreviada como e) e contém um scriptblock que recebe o objeto atual ($_) e retorna o valor calculado. A chave Name pode ser abreviada como n. Essa hashtable é passada para cmdlets como Select-Object ou Format-Table no lugar de um nome de propriedade simples.
Expression=}
A chave Expression (ou e) é o coração da propriedade calculada. Ela contém um scriptblock que é executado para cada objeto do pipeline. Dentro desse scriptblock, $_ representa o objeto atual. Você pode usar qualquer lógica do PowerShell: operadores, chamadas de métodos, condicionais, cálculos, etc.
Por exemplo, para criar uma propriedade que indica se um processo é crítico baseado no uso de CPU:
@{Name='Status'; Expression={ if ($_.CPU -gt 100) { 'Crítico' } else { 'Normal' } }}Além de Name e Expression, você pode usar outras chaves opcionais para controlar a formatação, como FormatString (para aplicar um formato .NET), Width (para tabelas), Alignment (para alinhamento), entre outras. Essas opções são especialmente úteis com Format-Table.
Em Select e Format
As propriedades calculadas podem ser usadas em cmdlets que aceitam listas de propriedades, principalmente Select-Object e Format-Table (e também Format-List). Quando você usa Select-Object, as propriedades calculadas são adicionadas aos objetos de saída, criando objetos com essas novas propriedades. Já no Format-Table, elas afetam apenas a exibição, sem alterar os objetos.
Exemplo com Select-Object:
Get-Process | Select-Object Name, @{Name='MemMB'; Expression={ [math]::Round($_.WorkingSet64 / 1MB, 2) }}Isso produzirá uma lista de processos com as propriedades Name e MemMB (memória em MB). O resultado é um objeto com essas propriedades, que pode ser usado em outros cmdlets.
Exemplo com Format-Table:
Get-ChildItem -File | Format-Table Name, @{Name='TamanhoMB'; Expression={ $_.Length / 1MB }; FormatString='N2'}Aqui, a coluna 'TamanhoMB' é exibida com duas casas decimais graças ao FormatString. Lembre-se de que Format-Table é para exibição; os objetos originais não são modificados.
Casos de uso
As propriedades calculadas são extremamente úteis em várias situações:
- Conversão de unidades: exibir tamanhos em KB, MB, GB, ou temperaturas em °C/°F.
- Formatação de datas: exibir datas em formato personalizado, como 'dd/MM/yyyy'.
- Combinação de propriedades: concatenar nome e sobrenome, endereço completo, etc.
- Lógica condicional: classificar itens como 'Alto', 'Médio', 'Baixo' com base em valores.
- Extração de informações: obter a extensão de um arquivo, o nome do diretório pai, etc.
- Valores calculados: somar, subtrair, multiplicar propriedades numéricas.
- Formatação de saída: criar relatórios legíveis com colunas personalizadas.
Por exemplo, para listar arquivos com sua extensão e tamanho em KB:
Get-ChildItem | Select-Object Name, Extension, @{Name='TamanhoKB'; Expression={ if($_.PSIsContainer) { 'N/A' } else { [math]::Round($_.Length / 1KB, 2) } }}Isso demonstra como tratar diretórios (que não têm tamanho) de forma especial.
Exemplos
Vamos explorar exemplos práticos que consolidam o aprendizado.
Exemplo 1: Listar serviços com status legível (em vez de 'Running' ou 'Stopped'):
Get-Service | Select-Object Name, DisplayName, @{Name='Estado'; Expression={ if($_.Status -eq 'Running') { 'Em execução' } else { 'Parado' } }}Exemplo 2: Calcular o tempo de atividade do sistema (uptime) em dias:
$os = Get-CimInstance Win32_OperatingSystem
$uptime = (Get-Date) - $os.LastBootUpTime
$os | Select-Object Caption, @{Name='UptimeDias'; Expression={ [math]::Round($uptime.TotalDays, 2) }}Exemplo 3: Formatar números de telefone em uma lista de contatos (simulação):
$contatos = @(
[PSCustomObject]@{Nome='Ana'; Telefone='11987654321'},
[PSCustomObject]@{Nome='Bruno'; Telefone='21988887777'}
)
$contatos | Select-Object Nome, @{Name='TelefoneFormatado'; Expression={ $tel = $_.Telefone; "($($tel.Substring(0,2))) $($tel.Substring(2,5))-$($tel.Substring(7))" }}Exemplo 4: Usando propriedades calculadas com Group-Object para criar resumos:
Get-Process | Group-Object ProcessName | Select-Object Name, @{Name='MemTotalMB'; Expression={ [math]::Round(($_.Group | Measure-Object WorkingSet64 -Sum).Sum / 1MB, 2) }}, CountEsses exemplos mostram a flexibilidade e o poder das propriedades calculadas.
Boas práticas
Ao usar propriedades calculadas, considere as seguintes boas práticas:
- Use nomes de propriedades claros e sem espaços (ou com aspas se necessário).
- Preste atenção à cultura ao formatar números (use
InvariantCulturese necessário). - Evite cálculos pesados dentro da expressão se estiver processando muitos objetos; considere pré-calcular em variáveis.
- Prefira
Select-Objectquando precisar reutilizar os dados; useFormat-Tableapenas para exibição. - Teste suas expressões em um único objeto antes de aplicar em larga escala.
Essas práticas ajudam a manter seus scripts eficientes e legíveis.
Referências
- Documentação oficial do Select-Object
- Documentação oficial do Format-Table
- about_Hash_Tables
- about_Script_Blocks
- Creating Custom Table Views
- about_Pipelines
Exercícios
- Exercício 1: Crie um comando que liste todos os processos com o nome e o uso de CPU em percentual (assuma que o valor de CPU é um número arbitrário). Use uma propriedade calculada para formatar a CPU como percentual com uma casa decimal.
- Exercício 2: Usando
Get-ChildItem, liste os arquivos de um diretório com o nome, o tamanho em MB (duas casas decimais) e a extensão. UseFormat-Tablepara exibir. - Exercício 3: Crie uma propriedade calculada que retorne o status de um serviço como 'Ativo' se estiver em execução, 'Parado' se parado, e 'Desconhecido' caso contrário. Teste com
Get-Servicee selecione Name, DisplayName e essa propriedade. - Exercício 4: Dado um array de números, use
Select-Objectcom uma propriedade calculada para mostrar cada número e seu quadrado. Use um pipeline comForEach-Objectpara gerar os números de 1 a 10. - Exercício 5: Escreva um script que liste os 5 processos com maior uso de memória, exibindo nome e memória em MB, ordenados de forma decrescente. Use propriedade calculada.
Get-Process | Select-Object Name, @{Name='CPUPercentual'; Expression={ [math]::Round($_.CPU, 1).ToString() + '%' }}Get-ChildItem -File | Format-Table Name, @{Name='TamanhoMB'; Expression={ [math]::Round($_.Length / 1MB, 2) }}, ExtensionGet-Service | Select-Object Name, DisplayName, @{Name='Estado'; Expression={ switch($_.Status) { 'Running' { 'Ativo' } 'Stopped' { 'Parado' } default { 'Desconhecido' } } }}1..10 | ForEach-Object { $_ } | Select-Object @{Name='Numero'; Expression={$_}}, @{Name='Quadrado'; Expression={$_ * $_}}Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5 Name, @{Name='MemMB'; Expression={ [math]::Round($_.WorkingSet64 / 1MB, 2) }}