Nesta aula, vamos explorar uma das tarefas mais comuns em administração e automação: trabalhar com arquivos CSV (Comma-Separated Values). O PowerShell oferece cmdlets nativos que facilitam a leitura e escrita desses arquivos, transformando-os em objetos que podem ser manipulados diretamente no pipeline. Isso significa que você pode importar dados de um CSV, filtrar, modificar e exportar novamente, tudo com poucas linhas de código.

Dominar CSV é essencial para integrar sistemas, gerar relatórios, importar listas de usuários, equipamentos ou qualquer dado tabular. Vamos começar com os comandos básicos e avançar para técnicas mais refinadas, como personalização de delimitadores e tratamento de dados complexos.

Import-Csv e Export-Csv

Os cmdlets Import-Csv e Export-Csv são as ferramentas centrais para trabalhar com CSV no PowerShell. O Export-Csv converte objetos em linhas de um arquivo CSV, enquanto o Import-Csv lê um arquivo CSV e cria objetos personalizados a partir das colunas. Esses cmdlets são simétricos: o que é exportado pode ser importado de volta, preservando a estrutura dos dados.

Vamos ver um exemplo básico de exportação. Suponha que temos uma lista de processos e queremos salvar as propriedades Name, Id e CPU em um arquivo:

Get-Process | Select-Object Name, Id, CPU | Export-Csv -Path "processos.csv" -NoTypeInformation

O parâmetro -NoTypeInformation evita que a primeira linha do arquivo contenha o nome do tipo (geralmente #TYPE System.Diagnostics.Process), que é desnecessário para a maioria dos usos. Sem esse parâmetro, o arquivo terá uma linha extra que pode atrapalhar a leitura por outros programas.

Para importar esse CSV de volta, usamos Import-Csv:

$dados = Import-Csv -Path "processos.csv"

O resultado é um array de objetos (PSCustomObject) onde cada propriedade corresponde a uma coluna do CSV. Podemos acessar os dados como qualquer objeto:

$dados | Where-Object { $_.CPU -gt 10 } | Format-Table

Objetos a partir de CSV

Quando você importa um CSV, o PowerShell cria automaticamente um PSCustomObject para cada linha, com propriedades nomeadas de acordo com o cabeçalho. Isso permite que você use todos os cmdlets de manipulação de objetos, como Where-Object, Sort-Object, Group-Object, etc. No entanto, é importante notar que todos os valores são strings. Se você precisar tratar números ou datas, deve converter explicitamente.

Vamos ver um exemplo prático. Suponha que temos um arquivo funcionarios.csv com colunas: Nome, Departamento, Salario. Ao importar, podemos calcular a média salarial por departamento:

$func = Import-Csv -Path "funcionarios.csv"
$func | Group-Object Departamento | ForEach-Object {
    $media = ($_.Group | Measure-Object -Property Salario -Average).Average
    [PSCustomObject]@{
        Departamento = $_.Name
        MediaSalarial = [math]::Round($media, 2)
    }
}

Note que Salario é tratado como string, mas o Measure-Object consegue converter automaticamente para número. Em cenários mais complexos, use [double] ou [int] para converter antes de operações matemáticas.

Outra técnica útil é adicionar propriedades calculadas. Por exemplo, criar uma coluna com o salário anual:

$func | Select-Object Nome, Departamento, Salario, @{Name='SalarioAnual'; Expression={[double]$_.Salario * 12}} | Export-Csv -Path "funcionarios_anual.csv" -NoTypeInformation

Delimitadores

Por padrão, o Import-Csv e Export-Csv usam vírgula como delimitador, que é o padrão para CSV. No entanto, muitas vezes os dados podem usar ponto e vírgula (comum em países onde a vírgula é usada como separador decimal) ou tabulação. Para lidar com isso, ambos os cmdlets possuem o parâmetro -Delimiter.

Exemplo de exportação com ponto e vírgula:

Get-Process | Select-Object Name, Id | Export-Csv -Path "processos_pv.csv" -Delimiter ';' -NoTypeInformation

E importação correspondente:

$processos = Import-Csv -Path "processos_pv.csv" -Delimiter ';'

Se o arquivo tiver um delimitador diferente, você deve especificá-lo corretamente, caso contrário o PowerShell pode interpretar as colunas de forma errada. Uma dica: ao importar um arquivo desconhecido, você pode inspecionar as primeiras linhas para identificar o delimitador.

Outro ponto importante é o encoding. O Export-Csv usa UTF-8 sem BOM por padrão (no Windows PowerShell 5.1, usa ASCII; no PowerShell 7+, UTF-8). Se você tiver caracteres acentuados, pode ser necessário especificar o encoding com o parâmetro -Encoding. Por exemplo:

Export-Csv -Path "dados.csv" -Encoding UTF8 -NoTypeInformation

Casos de uso

Os arquivos CSV são amplamente utilizados em ambientes de TI para troca de dados entre sistemas, importação em massa, geração de relatórios e integração com ferramentas como Excel, bancos de dados e APIs. No PowerShell, você pode combinar CSV com outros cmdlets para automatizar tarefas administrativas.

Exemplo 1: Criar usuários em massa no Active Directory

Suponha que você tenha um CSV com informações de novos funcionários: Nome, Sobrenome, Login, Departamento. Você pode ler o CSV e, para cada linha, criar um usuário no AD:

$usuarios = Import-Csv -Path "novos_funcionarios.csv"
foreach ($u in $usuarios) {
    New-ADUser -Name ($u.Nome + ' ' + $u.Sobrenome) -SamAccountName $u.Login -Department $u.Departamento -Enabled $true
}

Exemplo 2: Gerar relatório de espaço em disco

Podemos coletar informações de vários servidores e exportar para CSV, gerando um relatório consolidado. Suponha que temos uma lista de servidores em servidores.txt:

$servidores = Get-Content -Path "servidores.txt"
$resultado = foreach ($s in $servidores) {
    Get-CimInstance -ComputerName $s -ClassName Win32_LogicalDisk -Filter "DriveType=3" |
        Select-Object @{Name='Servidor'; Expression={$s}}, DeviceID, @{Name='EspacoLivreGB'; Expression={[math]::Round($_.FreeSpace/1GB,2)}}
}
$resultado | Export-Csv -Path "relatorio_disco.csv" -NoTypeInformation

Exemplo 3: Integração com APIs

Muitas APIs retornam dados em JSON, mas você pode convertê-los para CSV para facilitar a análise em Excel. Veja um exemplo com a API do GitHub:

$repos = Invoke-RestMethod -Uri "https://api.github.com/orgs/microsoft/repos" -Headers @{"User-Agent"="PowerShell"}
$repos | Select-Object name, html_url, stargazers_count | Export-Csv -Path "repos_microsoft.csv" -NoTypeInformation

Esses são apenas alguns exemplos. O CSV é uma ponte entre o PowerShell e outras ferramentas, tornando a automação mais flexível e os dados mais acessíveis.

Boas práticas e observações finais

  • Sempre use -NoTypeInformation ao exportar para evitar linhas indesejadas.
  • Verifique o encoding ao lidar com caracteres especiais (use -Encoding UTF8 no PowerShell 7+).
  • Considere usar ConvertTo-Csv e ConvertFrom-Csv quando você quiser trabalhar com CSV como string em vez de arquivo.
  • Lembre-se de que valores importados são strings; converta tipos quando necessário.
  • Para arquivos grandes, o Import-Csv pode ser lento; considere usar Import-Csv com streaming ou outras técnicas se o desempenho for crítico.

Referências

Exercícios

  1. Exercício 1: Crie um script que exporte a lista de serviços do Windows (nome, status, tipo de inicialização) para um arquivo CSV chamado "servicos.csv" usando Export-Csv. Em seguida, importe esse arquivo e exiba apenas os serviços que estão em execução (Running).

    ✓ Resposta:
    # Exportar serviços
    Get-Service | Select-Object Name, Status, StartType | Export-Csv -Path "servicos.csv" -NoTypeInformation
    
    # Importar e filtrar
    $servicos = Import-Csv -Path "servicos.csv"
    $servicos | Where-Object { $_.Status -eq 'Running' } | Format-Table
  2. Exercício 2: Dado um CSV com colunas "Nome" e "Idade", escreva um script que importe o arquivo, converta a idade para inteiro e calcule a média de idade das pessoas com mais de 30 anos.

    ✓ Resposta:
    $pessoas = Import-Csv -Path "pessoas.csv"
    $maiores = $pessoas | Where-Object { [int]$_.Idade -gt 30 }
    $media = ($maiores | Measure-Object -Property Idade -Average).Average
    Write-Host "Média de idade: $([math]::Round($media,2))"
  3. Exercício 3: Suponha que você tenha um arquivo CSV separado por ponto e vírgula. Importe-o corretamente e exporte-o novamente com delimitador vírgula.

    ✓ Resposta:
    $dados = Import-Csv -Path "dados_ponto_virgula.csv" -Delimiter ';'
    $dados | Export-Csv -Path "dados_virgula.csv" -Delimiter ',' -NoTypeInformation
  4. Exercício 4: Crie um script que leia um CSV de produtos (colunas: Nome, Preco, Quantidade) e adicione uma coluna calculada "Total" (Preco * Quantidade) e exporte o resultado para um novo CSV.

    ✓ Resposta:
    $produtos = Import-Csv -Path "produtos.csv"
    $produtos | Select-Object Nome, Preco, Quantidade, @{Name='Total'; Expression={[double]$_.Preco * [int]$_.Quantidade}} | Export-Csv -Path "produtos_total.csv" -NoTypeInformation
  5. Exercício 5: Escreva um script que importe um CSV de funcionários (Nome, Departamento, Salario) e exiba o total de salários por departamento, ordenado do maior para o menor.

    ✓ Resposta:
    $func = Import-Csv -Path "funcionarios.csv"
    $func | Group-Object Departamento | ForEach-Object {
        [PSCustomObject]@{
            Departamento = $_.Name
            TotalSalarios = ($_.Group | Measure-Object -Property Salario -Sum).Sum
        }
    } | Sort-Object TotalSalarios -Descending | Format-Table