Criando relatórios de sistema com PowerShell e exportando para CSV
1. Introdução aos relatórios de sistema com PowerShell
O PowerShell é uma ferramenta poderosa para administradores de sistemas que precisam gerar relatórios detalhados sobre o estado de servidores e estações de trabalho. Diferente de interfaces gráficas que exigem navegação manual, o PowerShell permite coletar, filtrar e exportar informações de forma programática e repetível.
A exportação para CSV (Comma-Separated Values) é particularmente vantajosa por três motivos principais: compatibilidade universal com ferramentas como Microsoft Excel e Google Sheets, facilidade de importação em bancos de dados e sistemas de monitoramento, e o formato leve que pode ser processado até mesmo em arquivos de texto simples.
Pré-requisitos básicos:
- PowerShell 5.1 ou superior (incluído no Windows 10/11 e Windows Server 2016+)
- Permissões de administrador local para acessar informações do sistema (WMI/CIM)
- Para relatórios remotos, permissões de administrador nos computadores alvo e WinRM habilitado
2. Coletando informações do hardware do sistema
O cmdlet Get-CimInstance é a forma moderna e recomendada para acessar informações do sistema via WMI (Windows Management Instrumentation). Vamos começar com um exemplo prático que coleta dados essenciais de hardware.
# Script: Inventário de Hardware Básico
$hardwareReport = @()
# CPU
$cpu = Get-CimInstance -ClassName Win32_Processor
$hardwareReport += [PSCustomObject]@{
Categoria = "CPU"
Nome = $cpu.Name
Núcleos = $cpu.NumberOfCores
Threads = $cpu.NumberOfLogicalProcessors
FrequênciaMHz = $cpu.MaxClockSpeed
}
# Memória RAM
$ram = Get-CimInstance -ClassName Win32_PhysicalMemory
$totalRAM = ($ram | Measure-Object -Property Capacity -Sum).Sum / 1GB
$hardwareReport += [PSCustomObject]@{
Categoria = "Memória RAM"
TotalGB = [math]::Round($totalRAM, 2)
Pentes = $ram.Count
}
# Discos
$disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
foreach ($disk in $disks) {
$hardwareReport += [PSCustomObject]@{
Categoria = "Disco"
Unidade = $disk.DeviceID
TamanhoGB = [math]::Round($disk.Size / 1GB, 2)
LivreGB = [math]::Round($disk.FreeSpace / 1GB, 2)
PercentualLivre = [math]::Round(($disk.FreeSpace / $disk.Size) * 100, 2)
}
}
# Placa-mãe e BIOS
$bios = Get-CimInstance -ClassName Win32_BIOS
$baseboard = Get-CimInstance -ClassName Win32_BaseBoard
$hardwareReport += [PSCustomObject]@{
Categoria = "BIOS"
Fabricante = $bios.Manufacturer
Versão = $bios.SMBIOSBIOSVersion
PlacaMãe = "$($baseboard.Manufacturer) $($baseboard.Product)"
}
$hardwareReport | Export-Csv -Path "C:\Relatorios\Hardware_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8
3. Obtendo dados de software e processos
Para listar programas instalados, o namespace Win32_Product deve ser evitado por ser lento e causar reconhecimento de pacotes. A abordagem recomendada é consultar o registro do Windows.
# Script: Relatório de Software Instalado
$software = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
$softwareReport = $software | Where-Object {
$_.DisplayName -and $_.DisplayName -notlike "*Update for*" -and $_.DisplayName -notlike "*Security Update*"
} | Select-Object @{N="Programa";E={$_.DisplayName}},
@{N="Versão";E={$_.DisplayVersion}},
@{N="Fabricante";E={$_.Publisher}},
@{N="DataInstalação";E={$_.InstallDate}}
# Processos ativos com consumo de recursos
$processReport = Get-Process | Select-Object Name, Id,
@{N="CPU(s)";E={[math]::Round($_.CPU, 2)}},
@{N="MemóriaMB";E={[math]::Round($_.WorkingSet64 / 1MB, 2)}},
@{N="Threads";E={$_.Threads.Count}}
# Serviços do Windows
$serviceReport = Get-Service | Select-Object Name, DisplayName, Status, StartType
# Exportação combinada
$softwareReport | Export-Csv "C:\Relatorios\Software_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
$processReport | Export-Csv "C:\Relatorios\Processos_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
$serviceReport | Export-Csv "C:\Relatorios\Servicos_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
4. Coletando informações de rede e usuários
Informações de rede e sessões de usuários são cruciais para auditoria e troubleshooting.
# Script: Relatório de Rede e Usuários
$networkReport = Get-NetAdapter | Where-Object {$_.Status -eq "Up"} | ForEach-Object {
$adapter = $_
$ipConfig = Get-NetIPAddress -InterfaceIndex $adapter.ifIndex -AddressFamily IPv4
$dns = Get-DnsClientServerAddress -InterfaceIndex $adapter.ifIndex
[PSCustomObject]@{
Adaptador = $adapter.Name
IP = $ipConfig.IPAddress
Máscara = $ipConfig.PrefixLength
Gateway = (Get-NetRoute -InterfaceIndex $adapter.ifIndex -DestinationPrefix "0.0.0.0/0").NextHop
DNS1 = $dns.ServerAddresses[0]
DNS2 = $dns.ServerAddresses[1]
MAC = $adapter.MacAddress
}
}
# Usuários logados
$userSessions = Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object UserName
$loggedUsers = @()
$sessions = quser 2>$null
if ($sessions) {
$loggedUsers = $sessions | Select-Object -Skip 1 | ForEach-Object {
$parts = $_ -split '\s+'
[PSCustomObject]@{
Usuário = $parts[0]
Sessão = $parts[1]
ID = $parts[2]
Estado = $parts[3]
}
}
}
# Compartilhamentos de rede
$shares = Get-SmbShare | Select-Object Name, Path, Description, ShareType
$networkReport | Export-Csv "C:\Relatorios\Rede_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
$loggedUsers | Export-Csv "C:\Relatorios\Usuarios_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
$shares | Export-Csv "C:\Relatorios\Compartilhamentos_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
5. Estruturando os dados e exportando para CSV
A qualidade do relatório depende de como os dados são estruturados antes da exportação. Use Select-Object para escolher apenas as propriedades relevantes, Sort-Object para ordenar e Group-Object para agrupar.
# Exemplo de estruturação avançada
$allProcesses = Get-Process | Group-Object -Property Company | ForEach-Object {
[PSCustomObject]@{
Fabricante = $_.Name
TotalProcessos = $_.Count
MemóriaTotalMB = [math]::Round(($_.Group | Measure-Object -Property WorkingSet64 -Sum).Sum / 1MB, 2)
Processos = ($_.Group.Name -join "; ")
}
} | Sort-Object -Property TotalProcessos -Descending
# Exportação com opções
$allProcesses | Export-Csv -Path "C:\Relatorios\ProcessosAgrupados.csv" `
-NoTypeInformation `
-Encoding UTF8 `
-Delimiter ";"
# Verificando a exportação
Import-Csv "C:\Relatorios\ProcessosAgrupados.csv" -Delimiter ";" | Format-Table -AutoSize
6. Automatizando e agendando relatórios periódicos
Crie funções reutilizáveis para gerar relatórios completos e agende-os no Windows Task Scheduler.
# Função principal de relatório
function New-SystemReport {
param(
[string]$OutputPath = "C:\Relatorios",
[string[]]$Computers = @($env:COMPUTERNAME)
)
foreach ($computer in $Computers) {
try {
$report = @()
# Coleta CPU
$cpu = Get-CimInstance -ComputerName $computer -ClassName Win32_Processor
$report += [PSCustomObject]@{
Computador = $computer
Categoria = "CPU"
Valor = $cpu.Name
Detalhe = "$($cpu.NumberOfCores) núcleos / $($cpu.NumberOfLogicalProcessors) threads"
}
# Coleta memória
$ram = Get-CimInstance -ComputerName $computer -ClassName Win32_PhysicalMemory
$totalRAM = [math]::Round(($ram | Measure-Object -Property Capacity -Sum).Sum / 1GB, 2)
$report += [PSCustomObject]@{
Computador = $computer
Categoria = "RAM"
Valor = "$totalRAM GB"
Detalhe = "$($ram.Count) pentes"
}
# Coleta disco C:
$disk = Get-CimInstance -ComputerName $computer -ClassName Win32_LogicalDisk -Filter "DeviceID='C:'"
$pctLivre = [math]::Round(($disk.FreeSpace / $disk.Size) * 100, 2)
$report += [PSCustomObject]@{
Computador = $computer
Categoria = "Disco C:"
Valor = "$([math]::Round($disk.Size/1GB,2)) GB"
Detalhe = "$([math]::Round($disk.FreeSpace/1GB,2)) GB livres ($pctLivre%)"
}
# Exporta
$filename = "$OutputPath\RelatorioSistema_$computer_$(Get-Date -Format 'yyyyMMdd').csv"
$report | Export-Csv -Path $filename -NoTypeInformation -Encoding UTF8
Write-Host "Relatório gerado: $filename" -ForegroundColor Green
}
catch {
Write-Warning "Erro ao processar $computer : $_"
}
}
}
# Uso: relatório semanal de desempenho
New-SystemReport -Computers @("SERVIDOR01", "SERVIDOR02", "WORKSTATION01")
Para agendar no Task Scheduler, crie uma tarefa básica que execute:
powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\SystemReport.ps1"
7. Boas práticas e tratamento de erros
Sempre valide dados ausentes e trate exceções para evitar relatórios corrompidos.
# Função segura para coleta de dados
function Get-SafeCimInstance {
param(
[string]$ClassName,
[string]$ComputerName = $env:COMPUTERNAME,
[string]$Filter = $null
)
try {
$params = @{
ClassName = $ClassName
ComputerName = $ComputerName
ErrorAction = "Stop"
}
if ($Filter) { $params.Filter = $Filter }
$result = Get-CimInstance @params
return $result
}
catch {
Write-Warning "Falha ao obter $ClassName de $ComputerName : $($_.Exception.Message)"
return $null
}
}
# Tratamento de valores nulos na exportação
$data = @()
$cpuInfo = Get-SafeCimInstance -ClassName "Win32_Processor"
if ($cpuInfo) {
$data += [PSCustomObject]@{
Propriedade = "CPU"
Valor = $cpuInfo.Name ?? "Não disponível"
Detalhe = "$($cpuInfo.NumberOfCores ?? 0) núcleos"
}
} else {
$data += [PSCustomObject]@{
Propriedade = "CPU"
Valor = "Erro na coleta"
Detalhe = "Verifique permissões e conectividade"
}
}
# Limpeza do CSV: remover linhas vazias e normalizar
$csvPath = "C:\Relatorios\RelatorioLimpo.csv"
$data | Export-Csv $csvPath -NoTypeInformation -Encoding UTF8
# Pós-processamento: remover aspas desnecessárias
(Get-Content $csvPath) -replace '"', '' | Set-Content $csvPath
Dicas finais:
- Use -Encoding UTF8 para suportar caracteres especiais
- Defina -NoTypeInformation para evitar a linha "#TYPE" no CSV
- Para relatórios remotos, configure corretamente o WinRM e o firewall
- Teste scripts em ambiente controlado antes de agendar em produção
Referências
- Documentação oficial do PowerShell sobre CIM — Guia completo sobre o uso de Get-CimInstance para consultar informações do sistema.
- Export-Csv no Microsoft Learn — Documentação oficial do cmdlet Export-Csv com todos os parâmetros e exemplos.
- Tutorial: Inventário de Hardware com PowerShell — Artigo prático da 4sysops sobre como criar scripts de inventário de hardware.
- Agendando tarefas no Windows com PowerShell e Task Scheduler — Guia detalhado sobre automação de scripts PowerShell usando o Agendador de Tarefas.
- Boas práticas para tratamento de erros em PowerShell — Artigo da comunidade PowerShell.org sobre como lidar com exceções e erros em scripts.
- PowerShell e WMI: Coletando informações de software instalado — Post do blog oficial da Microsoft sobre como listar programas instalados via registro.