Nesta aula, vamos colocar em prática tudo o que aprendemos até agora construindo um projeto completo: um inventário de sistema. O objetivo é criar um script que colete informações relevantes sobre o computador (hardware, sistema operacional, software instalado), formate essas informações de maneira legível e gere um relatório em formato HTML ou CSV. Além disso, vamos configurar o script para ser executado automaticamente em intervalos regulares, garantindo que o inventário esteja sempre atualizado.

Este projeto é um exemplo clássico de automação com PowerShell: você pode usá-lo em ambientes corporativos para manter um registro dos equipamentos, auxiliar no suporte técnico ou simplesmente para ter um diagnóstico rápido do seu próprio sistema. Vamos dividir o projeto em etapas: coleta, formatação, exportação e agendamento. Ao final, você terá um script robusto e reutilizável.

Coletando informações

O primeiro passo é reunir as informações do sistema. O PowerShell oferece uma variedade de cmdlets para isso. O cmdlet Get-ComputerInfo é um dos mais completos, pois retorna um objeto com dezenas de propriedades, como fabricante, modelo, versão do sistema operacional, memória total, entre outras. No entanto, ele pode ser lento em algumas máquinas porque consulta várias fontes. Para informações mais específicas, podemos usar cmdlets como Get-CimInstance (ou o antigo Get-WmiObject) para acessar classes WMI/CIM, como Win32_Processor, Win32_BIOS, Win32_OperatingSystem e Win32_LogicalDisk.

Além disso, é comum querer listar o software instalado. Podemos obter isso consultando o registro do Windows ou usando o cmdlet Get-Package (disponível no PackageManagement). Vamos criar uma função que coleta as principais informações e as armazena em um objeto personalizado. Isso facilita a formatação e exportação posterior.

Aqui está um exemplo de script para coleta de informações básicas:

function Get-SystemInventory {
    $computerInfo = Get-ComputerInfo
    $os = Get-CimInstance -ClassName Win32_OperatingSystem
    $cpu = Get-CimInstance -ClassName Win32_Processor
    $disk = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
    $bios = Get-CimInstance -ClassName Win32_BIOS

    # Criando um objeto personalizado com as informações principais
    $inventory = [PSCustomObject]@{
        ComputerName = $env:COMPUTERNAME
        Manufacturer = $computerInfo.Manufacturer
        Model = $computerInfo.Model
        SerialNumber = $bios.SerialNumber
        OSName = $os.Caption
        OSVersion = $os.Version
        LastBoot = $os.LastBootUpTime
        CPUName = $cpu.Name
        CPUCores = $cpu.NumberOfCores
        TotalRAM = [math]::Round($computerInfo.TotalPhysicalMemory / 1GB, 2)
        FreeDiskC = [math]::Round(($disk | Where-Object {$_.DeviceID -eq "C:"}).FreeSpace / 1GB, 2)
        TotalDiskC = [math]::Round(($disk | Where-Object {$_.DeviceID -eq "C:"}).Size / 1GB, 2)
    }

    return $inventory
}

# Executando a função
Get-SystemInventory

No script acima, usamos Get-ComputerInfo para dados gerais, mas também consultamos classes CIM específicas para garantir informações como número de série e espaço em disco. Observe que convertemos bytes para GB para facilitar a leitura. Você pode expandir essa função para incluir outros detalhes, como endereço IP, placa de vídeo ou lista de softwares instalados.

Formatando

Depois de coletar os dados, é hora de formatá-los para que fiquem apresentáveis. O PowerShell oferece vários cmdlets para isso: Format-Table, Format-List e ConvertTo-HTML. Para um relatório visual, o HTML é uma ótima opção, pois pode ser aberto em qualquer navegador e estilizado com CSS. Para dados tabulares, CSV é útil para importar em planilhas.

Vamos criar uma versão formatada do inventário. Primeiro, podemos exibir na tela com Format-List para uma visão detalhada, ou Format-Table para uma tabela compacta. Para o relatório final, usaremos ConvertTo-HTML para gerar uma página HTML com uma tabela.

Exemplo de formatação e geração de HTML:

# Coleta o inventário
$inventory = Get-SystemInventory

# Exibe na tela em formato de lista
$inventory | Format-List

# Converte para HTML com um pouco de estilo
$html = $inventory | ConvertTo-HTML -Property ComputerName, Manufacturer, Model, SerialNumber, OSName, OSVersion, LastBoot, CPUName, CPUCores, TotalRAM, FreeDiskC, TotalDiskC -Title "Inventário do Sistema" -Head ""

# Salva em arquivo
$html | Out-File -FilePath "$env:USERPROFILE\Desktop\inventario.html" -Encoding utf8

Write-Host "Relatório gerado em $env:USERPROFILE\Desktop\inventario.html" -ForegroundColor Green

O parâmetro -Head permite inserir CSS para melhorar a aparência. Você pode personalizar o HTML conforme necessário. Se preferir CSV, basta usar Export-Csv:

$inventory | Export-Csv -Path "$env:USERPROFILE\Desktop\inventario.csv" -NoTypeInformation

Lembre-se de que ConvertTo-HTML gera uma tabela simples; para relatórios mais elaborados, você pode construir o HTML manualmente ou usar fragmentos. Mas para este projeto, essa abordagem é suficiente.

Exportando relatório

A exportação é a etapa em que salvamos o relatório em um arquivo. Vimos acima como gerar HTML e CSV. É importante decidir onde salvar o arquivo. Uma boa prática é criar uma pasta específica para relatórios, por exemplo, C:\Inventario. Vamos melhorar o script para verificar se a pasta existe e criá-la se necessário. Além disso, podemos incluir a data no nome do arquivo para manter um histórico.

Vamos criar uma função que exporta o inventário em ambos os formatos (HTML e CSV) e também retorna o caminho dos arquivos gerados.

function Export-SystemInventory {
    param(
        [string]$Path = "C:\Inventario"
    )

    # Cria a pasta se não existir
    if (-not (Test-Path $Path)) {
        New-Item -ItemType Directory -Path $Path -Force | Out-Null
    }

    $date = Get-Date -Format "yyyyMMdd_HHmm"
    $inventory = Get-SystemInventory

    # Exporta para HTML
    $html = $inventory | ConvertTo-HTML -Property ComputerName, Manufacturer, Model, SerialNumber, OSName, OSVersion, LastBoot, CPUName, CPUCores, TotalRAM, FreeDiskC, TotalDiskC -Title "Inventário do Sistema" -Head ""
    $htmlPath = Join-Path $Path "inventario_$date.html"
    $html | Out-File -FilePath $htmlPath -Encoding utf8

    # Exporta para CSV
    $csvPath = Join-Path $Path "inventario_$date.csv"
    $inventory | Export-Csv -Path $csvPath -NoTypeInformation

    Write-Host "Relatórios gerados:" -ForegroundColor Green
    Write-Host "HTML: $htmlPath"
    Write-Host "CSV: $csvPath"
}

# Exemplo de uso
Export-SystemInventory -Path "C:\Inventario"

Neste script, usamos Get-Date para incluir um carimbo de data/hora no nome do arquivo, evitando sobrescritas. A função também retorna os caminhos para que você possa usá-los em outras automações, como enviar por e-mail.

Agendamento

Para que o inventário seja gerado automaticamente, podemos usar o Agendador de Tarefas do Windows. O PowerShell pode interagir com ele através do módulo ScheduledTasks. Vamos criar uma tarefa que executa nosso script diariamente em um horário específico.

Primeiro, precisamos salvar nosso script de inventário em um arquivo .ps1. Vamos supor que ele está em C:\Scripts\Inventario.ps1. A função Export-SystemInventory deve ser chamada no final do script. Depois, criamos a tarefa agendada.

Exemplo de agendamento:

# Define o caminho do script
$scriptPath = "C:\Scripts\Inventario.ps1"

# Cria a ação que executa o PowerShell com o script
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -File `"$scriptPath`""

# Define o gatilho: diariamente às 7h
$trigger = New-ScheduledTaskTrigger -Daily -At "07:00"

# Define o usuário que executará a tarefa (pode ser SYSTEM)
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest

# Registra a tarefa
Register-ScheduledTask -TaskName "InventarioSistema" -Action $action -Trigger $trigger -Principal $principal -Description "Gera inventário do sistema diariamente"

Se preferir agendar via interface gráfica, você pode usar o schtasks.exe ou o agendador manualmente. O comando acima cria uma tarefa que roda como SYSTEM, sem necessidade de senha. Para testar, você pode executar a tarefa manualmente:

Start-ScheduledTask -TaskName "InventarioSistema"

Lembre-se de que, se o script for executado como SYSTEM, ele precisará de permissões adequadas para acessar pastas como C:\Inventario. Verifique se o diretório existe e tem permissões de escrita para o usuário SYSTEM.

Boas práticas e observações finais

Ao desenvolver scripts de inventário, considere as seguintes boas práticas:

  • Modularize: separe a coleta, formatação e exportação em funções para facilitar a manutenção.
  • Trate erros: use try/catch para capturar falhas ao acessar informações do sistema.
  • Documente: inclua comentários explicando o propósito de cada bloco.
  • Segurança: ao agendar, use uma conta com privilégios mínimos necessários.
  • Teste: execute o script manualmente antes de agendar para garantir que tudo funciona.

Este projeto pode ser expandido para incluir informações de rede, lista de serviços, eventos do sistema, e até mesmo gerar relatórios em PDF. O PowerShell oferece infinitas possibilidades de automação.

Referências

Exercícios

  1. Exercício 1: Modifique a função Get-SystemInventory para incluir a quantidade de memória disponível (não apenas total) e o espaço livre em todos os discos, não apenas C:.
  2. ✓ Resposta:
    function Get-SystemInventory {
        $computerInfo = Get-ComputerInfo
        $os = Get-CimInstance -ClassName Win32_OperatingSystem
        $cpu = Get-CimInstance -ClassName Win32_Processor
        $disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
        $bios = Get-CimInstance -ClassName Win32_BIOS
    
        $diskInfo = foreach ($disk in $disks) {
            [PSCustomObject]@{
                Drive = $disk.DeviceID
                FreeSpaceGB = [math]::Round($disk.FreeSpace / 1GB, 2)
                TotalSizeGB = [math]::Round($disk.Size / 1GB, 2)
            }
        }
    
        $inventory = [PSCustomObject]@{
            ComputerName = $env:COMPUTERNAME
            Manufacturer = $computerInfo.Manufacturer
            Model = $computerInfo.Model
            SerialNumber = $bios.SerialNumber
            OSName = $os.Caption
            OSVersion = $os.Version
            LastBoot = $os.LastBootUpTime
            CPUName = $cpu.Name
            CPUCores = $cpu.NumberOfCores
            TotalRAM = [math]::Round($computerInfo.TotalPhysicalMemory / 1GB, 2)
            FreeRAM = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
            Disks = $diskInfo
        }
    
        return $inventory
    }
  3. Exercício 2: Crie uma função que exporte o inventário em formato JSON, além de HTML e CSV.
  4. ✓ Resposta:
    function Export-SystemInventoryJson {
        param([string]$Path = "C:\Inventario")
        if (-not (Test-Path $Path)) { New-Item -ItemType Directory -Path $Path -Force | Out-Null }
        $inventory = Get-SystemInventory
        $jsonPath = Join-Path $Path "inventario_$(Get-Date -Format 'yyyyMMdd_HHmm').json"
        $inventory | ConvertTo-Json -Depth 3 | Out-File -FilePath $jsonPath -Encoding utf8
        Write-Host "JSON exportado para $jsonPath"
    }
  5. Exercício 3: Agende o script para ser executado toda segunda-feira às 9h, usando o cmdlet Register-ScheduledTask.
  6. ✓ Resposta:
    $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -File `"C:\Scripts\Inventario.ps1`""
    $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At "09:00"
    $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
    Register-ScheduledTask -TaskName "InventarioSemanal" -Action $action -Trigger $trigger -Principal $principal -Description "Inventário semanal"
  7. Exercício 4: Escreva um código que envie um e-mail com o relatório em anexo, usando Send-MailMessage (ou Send-MailKitMessage se disponível).
  8. ✓ Resposta:
    $smtpServer = "smtp.seudominio.com"
    $from = "inventario@seudominio.com"
    $to = "admin@seudominio.com"
    $subject = "Inventário do Sistema"
    $body = "Segue o relatório de inventário."
    $attachment = "C:\Inventario\inventario_$(Get-Date -Format 'yyyyMMdd_HHmm').html"
    
    Send-MailMessage -SmtpServer $smtpServer -From $from -To $to -Subject $subject -Body $body -Attachments $attachment
  9. Exercício 5: Implemente tratamento de erro na função Get-SystemInventory para que, se Get-ComputerInfo falhar, o script continue usando Get-CimInstance.
  10. ✓ Resposta:
    function Get-SystemInventory {
        try {
            $computerInfo = Get-ComputerInfo -ErrorAction Stop
        } catch {
            Write-Warning "Get-ComputerInfo falhou, usando CIM"
            $computerInfo = Get-CimInstance -ClassName Win32_ComputerSystem
        }
        # ... resto do código
    }