Bem-vindo à aula sobre WMI e CIM no PowerShell! Nesta aula, vamos explorar dois conceitos fundamentais para administração de sistemas Windows: WMI (Windows Management Instrumentation) e CIM (Common Information Model). Entender a diferença entre eles e saber usar o cmdlet Get-CimInstance é essencial para automatizar tarefas de gerenciamento, coleta de informações e monitoramento de ambientes Windows.

O WMI é a implementação da Microsoft do padrão CIM, que permite acessar informações de hardware, software e configuração do sistema. Por muitos anos, os administradores usavam cmdlets como Get-WmiObject para consultar essas informações. No entanto, o PowerShell trouxe uma abordagem mais moderna e eficiente com o Get-CimInstance, que usa o protocolo WS-Management e é compatível com sistemas não Windows. Vamos mergulhar nesse mundo e aprender a usar essas ferramentas de forma prática.

Get-CimInstance

O cmdlet Get-CimInstance é a forma recomendada de consultar informações do sistema no PowerShell moderno. Ele faz parte do módulo CimCmdlets e usa o padrão CIM, que é um padrão aberto para representação de informações de gerenciamento. Diferente do Get-WmiObject, que usa a tecnologia DCOM, o Get-CimInstance usa o protocolo WS-Management (WSMan), que é mais leve, seguro e funciona tanto em máquinas locais quanto remotas, inclusive com sistemas Linux e macOS que tenham o Open Management Infrastructure (OMI) instalado.

Uma das principais vantagens do Get-CimInstance é que ele retorna objetos com metadados mais ricos, permitindo que você use a pipeline do PowerShell de forma mais eficiente. Além disso, ele suporta operações assíncronas e a possibilidade de criar classes CIM personalizadas. Vamos ver como usá-lo na prática.

# Sintaxe básica para consultar informações da BIOS
Get-CimInstance -ClassName Win32_BIOS

O parâmetro -ClassName é obrigatório e especifica a classe CIM que você deseja consultar. Existem milhares de classes disponíveis, como Win32_Process, Win32_OperatingSystem, Win32_ComputerSystem, entre outras. Você também pode usar o parâmetro -Namespace para especificar um namespace diferente do padrão (root/cimv2).

Outra funcionalidade importante é o parâmetro -Filter, que permite filtrar os resultados de forma semelhante a uma consulta SQL. Por exemplo, para listar apenas processos com mais de 100 MB de memória:

Get-CimInstance -ClassName Win32_Process | Where-Object { $_.WorkingSetSize -gt 100MB }

Ou usando o filtro diretamente:

Get-CimInstance -ClassName Win32_Process -Filter "WorkingSetSize > 104857600"

O Get-CimInstance também permite consultas remotas usando o parâmetro -ComputerName. Isso é especialmente útil para administrar vários servidores sem precisar de sessões separadas.

Consultando o sistema

Vamos explorar alguns exemplos práticos de consultas ao sistema usando o Get-CimInstance. Essas consultas são comuns no dia a dia de um administrador de sistemas.

1. Informações do sistema operacional:

Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object Caption, Version, BuildNumber, OSArchitecture

Isso retorna o nome do sistema operacional, versão, número de build e arquitetura.

2. Informações de hardware:

Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object Manufacturer, Model, TotalPhysicalMemory, NumberOfProcessors

Mostra fabricante, modelo, memória total e número de processadores.

3. Listar serviços e seus estados:

Get-CimInstance -ClassName Win32_Service | Select-Object Name, State, StartMode, PathName

Lista todos os serviços, indicando se estão em execução ou parados, o tipo de inicialização e o caminho do executável.

4. Discos e volumes:

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" | Select-Object DeviceID, VolumeName, Size, FreeSpace

O filtro DriveType=3 seleciona apenas discos locais fixos. Você pode ver o espaço total e livre de cada partição.

5. Processos em execução:

Get-CimInstance -ClassName Win32_Process | Select-Object Name, ProcessId, WorkingSetSize, ExecutablePath | Sort-Object WorkingSetSize -Descending | Select-Object -First 5

Lista os cinco processos que mais consomem memória.

Esses exemplos mostram como é fácil obter informações detalhadas do sistema com apenas algumas linhas de código. O Get-CimInstance é muito mais eficiente e flexível do que os cmdlets antigos.

vs WMI legado

Se você já trabalhou com PowerShell, provavelmente conhece o Get-WmiObject, que era o cmdlet padrão para consultas WMI até o PowerShell 5.1. No entanto, a Microsoft recomenda o uso do Get-CimInstance em vez do Get-WmiObject por várias razões:

  • Protocolo: Get-WmiObject usa DCOM, que é pesado e pode ser bloqueado por firewalls. Get-CimInstance usa WS-Management (WSMan), que é baseado em HTTP/HTTPS e mais fácil de configurar em redes.
  • Compatibilidade: O CIM é um padrão aberto, então o Get-CimInstance pode ser usado para consultar sistemas que não sejam Windows, como Linux com OMI.
  • Performance: O Get-CimInstance é geralmente mais rápido e consome menos recursos, especialmente em consultas remotas.
  • Extensibilidade: O CIM permite criar classes personalizadas e usar provedores mais modernos.
  • Suporte futuro: O Get-WmiObject foi removido no PowerShell 7, portanto, scripts que o usam não funcionarão em versões novas. O Get-CimInstance é o futuro.

Embora o Get-WmiObject ainda funcione em versões anteriores ao PowerShell 7, é importante migrar seus scripts para o Get-CimInstance agora. A sintaxe é muito semelhante, mas alguns parâmetros mudaram. Por exemplo, no Get-WmiObject, o filtro era passado com o parâmetro -Filter, e no Get-CimInstance também, mas os valores podem ser ligeiramente diferentes. Além disso, o Get-CimInstance retorna objetos com propriedades que podem ser acessadas de forma mais consistente.

Vamos comparar uma consulta nos dois cmdlets:

# WMI legado
Get-WmiObject -Class Win32_Process -Filter "Name='powershell.exe'" | Select-Object Name, ProcessId

# CIM moderno
Get-CimInstance -ClassName Win32_Process -Filter "Name='powershell.exe'" | Select-Object Name, ProcessId

Os resultados são os mesmos, mas o segundo é o recomendado. Para facilitar a migração, você pode usar o módulo CimCmdlets que oferece aliases como gcim para Get-CimInstance.

Exemplos

Vamos colocar em prática tudo o que aprendemos com exemplos mais complexos e úteis.

Exemplo 1: Relatório de hardware completo

Crie um script que coleta informações do processador, memória, disco e sistema operacional e gera um relatório formatado.

$computer = Get-CimInstance -ClassName Win32_ComputerSystem
$os = Get-CimInstance -ClassName Win32_OperatingSystem
$cpu = Get-CimInstance -ClassName Win32_Processor
$disk = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"

$report = [PSCustomObject]@{
    ComputerName = $computer.Name
    Manufacturer = $computer.Manufacturer
    Model = $computer.Model
    OS = $os.Caption
    Version = $os.Version
    CPU = $cpu.Name
    TotalRAM = [math]::Round($computer.TotalPhysicalMemory / 1GB, 2)
    DiskSpace = ($disk | ForEach-Object { "$($_.DeviceID) $([math]::Round($_.FreeSpace / 1GB, 2)) GB free of $([math]::Round($_.Size / 1GB, 2)) GB" }) -join "; "
}

$report | Format-List

Exemplo 2: Verificar se um serviço está em execução

$serviceName = "Spooler"
$service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$serviceName'"
if ($service.State -eq "Running") {
    Write-Host "O serviço $serviceName está em execução."
} else {
    Write-Host "O serviço $serviceName não está em execução. Estado atual: $($service.State)"
}

Exemplo 3: Consulta remota a vários computadores

Você pode usar o parâmetro -ComputerName para consultar vários servidores de uma vez. Vamos verificar o espaço em disco de uma lista de servidores.

$servers = @("SERVER01", "SERVER02", "SERVER03")
foreach ($server in $servers) {
    try {
        $disk = Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $server -Filter "DriveType=3"
        foreach ($d in $disk) {
            [PSCustomObject]@{
                Server = $server
                Drive = $d.DeviceID
                FreeSpaceGB = [math]::Round($d.FreeSpace / 1GB, 2)
                TotalSpaceGB = [math]::Round($d.Size / 1GB, 2)
            }
        }
    } catch {
        Write-Warning "Falha ao consultar $server : $_"
    }
}

Exemplo 4: Criar uma classe CIM personalizada

O CIM permite criar classes personalizadas para armazenar informações. Vamos criar uma classe para representar um usuário do sistema.

# Criar uma classe CIM personalizada
New-CimInstance -ClassName My_User -Namespace root/cimv2 -Property @{
    Name = "João Silva"
    Age = 30
    Email = "joao@example.com"
}

# Recuperar a classe
Get-CimInstance -ClassName My_User

Isso cria uma instância da classe My_User no namespace root/cimv2. Você pode usar essa técnica para armazenar dados de configuração personalizados.

Exemplo 5: Monitorar eventos do sistema

Você pode usar o Register-CimIndicationEvent para monitorar eventos, como a criação de um processo. Vamos monitorar quando o Bloco de Notas for aberto.

Register-CimIndicationEvent -ClassName Win32_ProcessStartTrace -SourceIdentifier "ProcessStarted" -Action {
    $event = $event.SourceEventArgs.NewEvent
    if ($event.ProcessName -eq "notepad.exe") {
        Write-Host "Bloco de Notas iniciado com PID $($event.ProcessID)"
    }
}

# Para parar o monitoramento, use:
# Unregister-Event -SourceIdentifier "ProcessStarted"

Esses exemplos mostram a versatilidade do Get-CimInstance e do CIM. Agora você pode explorar ainda mais as possibilidades.

Boas práticas

Ao trabalhar com CIM, siga estas boas práticas para garantir eficiência e segurança:

  • Prefira sempre Get-CimInstance em vez de Get-WmiObject em scripts novos.
  • Use o parâmetro -Filter para filtrar no servidor, em vez de trazer todos os objetos e filtrar no cliente. Isso reduz o tráfego de rede e melhora a performance.
  • Use -ComputerName para consultas remotas, mas lembre-se de configurar corretamente o WinRM (Windows Remote Management) e as permissões de firewall.
  • Quando precisar de informações específicas, selecione apenas as propriedades necessárias com Select-Object para reduzir a quantidade de dados transferidos.
  • Para consultas complexas, considere usar Get-CimInstance com a classe Win32_* adequada e, se necessário, use a sintaxe de consulta WQL (WMI Query Language) com o parâmetro -Query.
  • Teste seus scripts em um ambiente de laboratório antes de executar em produção.

Referências

Exercícios

  1. Escreva um comando PowerShell que use Get-CimInstance para listar todos os serviços que estão em execução no momento, exibindo apenas o nome e o caminho do executável.
  2. ✓ Resposta:
    Get-CimInstance -ClassName Win32_Service -Filter "State='Running'" | Select-Object Name, PathName
  3. Como você faria para obter a quantidade total de memória física do computador usando Get-CimInstance? Escreva o comando.
  4. ✓ Resposta:
    Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object TotalPhysicalMemory
  5. Qual é a diferença principal entre Get-WmiObject e Get-CimInstance? Explique em termos de protocolo.
  6. ✓ Resposta: O Get-WmiObject usa o protocolo DCOM, enquanto o Get-CimInstance usa o protocolo WS-Management (WSMan). O WSMan é mais leve, seguro e funciona melhor em redes, além de ser compatível com sistemas não Windows.
  7. Escreva um script que consulte o espaço livre em disco de todos os discos fixos locais e exiba uma mensagem de alerta se o espaço livre for menor que 10 GB.
  8. ✓ Resposta:
    $disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
    foreach ($disk in $disks) {
        $freeGB = [math]::Round($disk.FreeSpace / 1GB, 2)
        if ($freeGB -lt 10) {
            Write-Warning "Disco $($disk.DeviceID) com apenas $freeGB GB livres!"
        } else {
            Write-Host "Disco $($disk.DeviceID) tem $freeGB GB livres."
        }
    }
  9. Explique como você faria para consultar informações de um computador remoto usando Get-CimInstance. Inclua os parâmetros necessários.
  10. ✓ Resposta: Para consultar um computador remoto, use o parâmetro -ComputerName com o nome ou IP do computador. Por exemplo:
    Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName "SERVER01"
    É necessário que o WinRM esteja habilitado na máquina remota e que você tenha permissões adequadas.