Comparar objetos é uma tarefa comum na administração de sistemas e automação. No PowerShell, o cmdlet Compare-Object permite comparar duas coleções de objetos e identificar as diferenças entre elas. Ele é útil para verificar se dois conjuntos de dados são iguais, encontrar itens que existem em apenas uma das listas ou detectar mudanças ao longo do tempo.

Nesta aula, vamos explorar o funcionamento do Compare-Object, seus parâmetros e como interpretar os resultados. Veremos exemplos práticos que demonstram seu uso em cenários reais, como comparação de arquivos, usuários e processos.

Compare-Object

O cmdlet Compare-Object compara dois conjuntos de objetos: um conjunto de referência (-ReferenceObject) e um conjunto de diferença (-DifferenceObject). Ele retorna objetos que indicam quais itens estão presentes em apenas um dos conjuntos ou em ambos. A saída inclui uma propriedade SideIndicator que mostra de que lado o item é único: <= indica que o item está apenas no conjunto de referência, => indica que está apenas no conjunto de diferença.

A sintaxe básica é:

Compare-Object -ReferenceObject @(1,2,3) -DifferenceObject @(2,3,4)

Isso retornaria:

InputObject SideIndicator
----------- -------------
          1 <=
          4 =>

Por padrão, a comparação é feita por valor, mas você pode especificar propriedades com o parâmetro -Property para comparar objetos complexos.

Diferenças

As diferenças são identificadas através do SideIndicator. Existem três possibilidades:

  • <=: O item está apenas no conjunto de referência (lado esquerdo).
  • =>: O item está apenas no conjunto de diferença (lado direito).
  • Sem indicador (se usar -IncludeEqual): O item está presente em ambos os conjuntos.

Você pode personalizar a comparação com vários parâmetros:

  • -ExcludeDifferent: Exibe apenas os itens iguais.
  • -IncludeEqual: Inclui itens iguais na saída.
  • -PassThru: Passa os objetos originais em vez de objetos Compare-Object, útil para encadear comandos.
  • -CaseSensitive: Torna a comparação sensível a maiúsculas/minúsculas.
  • -SyncWindow: Define o número de elementos para sincronização em comparações sequenciais.

Por exemplo, para incluir itens iguais:

Compare-Object -ReferenceObject @(1,2,3) -DifferenceObject @(2,3,4) -IncludeEqual

Saída:

InputObject SideIndicator
----------- -------------
          1 <=
          2 ==
          3 ==
          4 =>

Casos de uso

O Compare-Object é amplamente utilizado em scripts de automação e administração. Alguns casos comuns:

  • Sincronização de arquivos: Comparar listas de arquivos em duas pastas para identificar quais precisam ser copiados ou removidos.
  • Validação de configurações: Comparar configurações atuais com um baseline para detectar alterações.
  • Gerenciamento de usuários: Comparar listas de usuários de dois sistemas (ex.: AD vs CSV) para encontrar discrepâncias.
  • Testes de software: Verificar se a saída de um comando corresponde ao esperado.
  • Auditoria de alterações: Comparar snapshots de estado do sistema em momentos diferentes.

Por exemplo, para comparar dois arquivos CSV:

$csv1 = Import-Csv -Path "C:\dados1.csv"
$csv2 = Import-Csv -Path "C:\dados2.csv"
Compare-Object -ReferenceObject $csv1 -DifferenceObject $csv2 -Property "Nome","Idade"

Exemplos

Exemplo 1: Comparar arrays simples

$ref = @(10,20,30)
$diff = @(20,30,40)
Compare-Object -ReferenceObject $ref -DifferenceObject $diff

Saída:

InputObject SideIndicator
----------- -------------
         10 <=
         40 =>

Exemplo 2: Comparar objetos com propriedades

$user1 = [PSCustomObject]@{Name="Alice"; Age=30}
$user2 = [PSCustomObject]@{Name="Bob"; Age=25}
$user3 = [PSCustomObject]@{Name="Alice"; Age=30}
Compare-Object -ReferenceObject $user1 -DifferenceObject $user2,$user3 -Property Name,Age

Saída:

Name  Age SideIndicator
----  --- -------------
Bob    25 =>
Alice  30 ==

Exemplo 3: Comparar listas de arquivos

$pastas1 = Get-ChildItem -Path "C:\pastaA" -File
$pastas2 = Get-ChildItem -Path "C:\pastaB" -File
Compare-Object -ReferenceObject $pastas1 -DifferenceObject $pastas2 -Property Name,Length

Isso mostra arquivos que diferem em nome ou tamanho entre as pastas.

Exemplo 4: Usar -PassThru para processar objetos originais

$ref = Get-Process -Name "notepad"
$diff = Get-Process -Name "notepad","calc"
Compare-Object -ReferenceObject $ref -DifferenceObject $diff -PassThru | Where-Object {$_.SideIndicator -eq "=>"} | Stop-Process

Isso para processos que estão apenas no conjunto de diferença (calc).

Boas práticas

  • Sempre especifique -Property ao comparar objetos complexos para evitar comparações por referência.
  • Use -IncludeEqual quando quiser confirmar que não há diferenças.
  • Combine Compare-Object com Where-Object e ForEach-Object para ações baseadas nas diferenças.
  • Para grandes conjuntos de dados, considere usar HashSet ou índices para melhor desempenho.

Referências

Exercícios

  1. Crie dois arrays com números de 1 a 5 e de 3 a 7. Use Compare-Object para exibir os números que estão apenas no primeiro array.

    ✓ Resposta:
    $arr1 = 1..5
    $arr2 = 3..7
    Compare-Object -ReferenceObject $arr1 -DifferenceObject $arr2 | Where-Object {$_.SideIndicator -eq "<="}
  2. Compare dois objetos personalizados com as propriedades Nome e Idade. Inclua os itens iguais na saída.

    ✓ Resposta:
    $obj1 = [PSCustomObject]@{Nome="João"; Idade=30}
    $obj2 = [PSCustomObject]@{Nome="Maria"; Idade=25}
    $obj3 = [PSCustomObject]@{Nome="João"; Idade=30}
    Compare-Object -ReferenceObject $obj1 -DifferenceObject $obj2,$obj3 -Property Nome,Idade -IncludeEqual
  3. Utilize Compare-Object para listar os processos que estão em execução no momento atual, mas não estavam há 5 segundos (simule dois snapshots).

    ✓ Resposta:
    $snapshot1 = Get-Process
    Start-Sleep -Seconds 5
    $snapshot2 = Get-Process
    Compare-Object -ReferenceObject $snapshot1 -DifferenceObject $snapshot2 -Property Id,ProcessName | Where-Object {$_.SideIndicator -eq "=>"}
  4. Compare duas listas de arquivos em pastas diferentes e exiba apenas os arquivos que estão na primeira pasta mas não na segunda (considere nome e tamanho).

    ✓ Resposta:
    $pastaA = Get-ChildItem -Path "C:\PastaA" -File
    $pastaB = Get-ChildItem -Path "C:\PastaB" -File
    Compare-Object -ReferenceObject $pastaA -DifferenceObject $pastaB -Property Name,Length | Where-Object {$_.SideIndicator -eq "<="}
  5. Crie um script que use Compare-Object para verificar se dois arquivos CSV (com colunas Nome e Email) são idênticos. Exiba uma mensagem se forem iguais ou liste as diferenças.

    ✓ Resposta:
    $csv1 = Import-Csv -Path "C:\dados1.csv"
    $csv2 = Import-Csv -Path "C:\dados2.csv"
    $diferencas = Compare-Object -ReferenceObject $csv1 -DifferenceObject $csv2 -Property Nome,Email
    if ($diferencas) {
        Write-Host "Diferenças encontradas:"
        $diferencas
    } else {
        Write-Host "Os arquivos são idênticos."
    }