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) }}, Count

Esses 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 InvariantCulture se necessário).
  • Evite cálculos pesados dentro da expressão se estiver processando muitos objetos; considere pré-calcular em variáveis.
  • Prefira Select-Object quando precisar reutilizar os dados; use Format-Table apenas 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

Exercícios

  1. 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.
  2. ✓ Resposta:
    Get-Process | Select-Object Name, @{Name='CPUPercentual'; Expression={ [math]::Round($_.CPU, 1).ToString() + '%' }}
  3. 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. Use Format-Table para exibir.
  4. ✓ Resposta:
    Get-ChildItem -File | Format-Table Name, @{Name='TamanhoMB'; Expression={ [math]::Round($_.Length / 1MB, 2) }}, Extension
  5. 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-Service e selecione Name, DisplayName e essa propriedade.
  6. ✓ Resposta:
    Get-Service | Select-Object Name, DisplayName, @{Name='Estado'; Expression={ switch($_.Status) { 'Running' { 'Ativo' } 'Stopped' { 'Parado' } default { 'Desconhecido' } } }}
  7. Exercício 4: Dado um array de números, use Select-Object com uma propriedade calculada para mostrar cada número e seu quadrado. Use um pipeline com ForEach-Object para gerar os números de 1 a 10.
  8. ✓ Resposta:
    1..10 | ForEach-Object { $_ } | Select-Object @{Name='Numero'; Expression={$_}}, @{Name='Quadrado'; Expression={$_ * $_}}
  9. 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.
  10. ✓ Resposta:
    Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5 Name, @{Name='MemMB'; Expression={ [math]::Round($_.WorkingSet64 / 1MB, 2) }}