Comparação de Arrays Facilitada com PowerShell

Usando um pouco de PowerShell kung-fu, você pode facilmente comparar matrizes PowerShell de todos os tipos de objetos. Existem muitos cenários diferentes em que você pode se encontrar, então vamos explorar e ver as maneiras como podemos construir o PowerShell para comparar matrizes.

Para determinar a melhor maneira de comparar matrizes, primeiro você deve descobrir quais tipos de elementos estão em ambas as matrizes.

  • Ambas as matrizes contêm o mesmo tipo de objeto?
  • Ambas as matrizes têm o mesmo número de elementos?
  • Há tipos diferentes de objetos em cada matriz?

Você deve conhecer a resposta para cada uma dessas perguntas antes de poder comparar com precisão as matrizes. Vamos cobrir cada cenário.

Comparando Matrizes de Strings

Uma das maneiras mais fáceis de comparar matrizes com PowerShell é se você tiver duas matrizes contendo apenas strings. Quando você se encontrar nessa posição, você tem algumas maneiras diferentes de comparar strings nas matrizes.

Usando os Operadores -Contains ou -In

O operador -contains é um operador do PowerShell que permite verificar se um objeto está em uma coleção. O operador -contains nativamente não entende coleções, mas você pode construir código para fazê-lo funcionar conforme desejar.

Vamos supor que uma coleção (matriz) contenha quatro strings como abaixo.

$array = @('blue','red','purple','pink')

O operador -contains funciona verificando se uma única string está naquela matriz assim:

$array -contains 'pink'

Quando a coleção à esquerda contém essa string, o PowerShell retornará Verdadeiro. Se não, retornará Falso.

PowerShell -contains Operator

Podemos comparar arrays usando o operador `-contains` lendo cada string em um array e verificando se o outro array contém essa string.

Vamos dizer que eu queira comparar dois arrays para ver quais strings no primeiro array existem no segundo array.

$array = @('blue','red','purple','pink')
$array2 = @('brown','red','black','yellow')

$array | ForEach-Object {
    if ($array2 -contains $_) {
        Write-Host "`$array2 contains the `$array1 string [$_]"
    }
}

Você também pode usar o operador `-in`, que é idêntico ao operador `-contains`, mas a sintaxe é oposta. Ao usar o operador `-contains`, o array é definido no lado esquerdo. Ao usar o operador `-in`, o array é definido no lado direito, como abaixo:

$array | ForEach-Object {
    if ($_ -in $array2) {
        Write-Host "`$array2 contains the `$array1 string [$_]"
    }
}

Usando Where-Object

Alternativamente, você também pode usar o cmdlet Where-Object para retornar todas as strings em um array no outro, como abaixo.

$array | Where-Object -FilterScript { $_ -in $array2 }

Usando o Cmdlet Compare-Object

Você também pode usar o PowerShell para comparar arrays usando o cmdlet `Compare-Object`. Este cmdlet recebe um objeto de referência e um objeto de diferença e retorna um indicador lateral indicando quais elementos estão e não estão em cada array.

Compare-Object -ReferenceObject $array -DifferenceObject $array2
Using Compare-Object

Você pode ver abaixo que o cmdlet `Compare-Object` permite comparar ambos os arrays de uma vez. Se a propriedade `SideIndicator` for `= >`, isso significa que o valor `InputObject` retornado está no valor `DifferenceObject` e não no valor `ReferenceObject`, e vice-versa para o indicador lateral `< =`.

Por padrão, Compare-Object retorna as diferenças. Você também pode retornar todas as strings em cada array que estão em ambos usando o parâmetro IncludeEqual.

Comparing arrays with Compare-Object

Comparando Arrays de Objetos Complexos

Bastante simples, não é? Agora, vamos introduzir objetos na equação. Digamos que temos um campo em nosso banco de dados de RH e gostaríamos de preencher isso no campo de descrição do Active Directory. Antes de fazer isso, primeiro precisamos ter um identificador comum. Em meu ambiente, há um número de funcionário tanto no banco de dados de RH quanto no atributo personalizado do Active Directory. Então, vamos tentar fazer essa correspondência.

Primeiro, vejamos o que acontece se tentarmos nossa abordagem anterior. Aqui está o arquivo CSV que estamos usando.

CSV output

Aqui está como obtenho nossos dois conjuntos de dados.

$ad_users = Get-AdUser -Filter {enabled -eq $true} -Properties employeeNumber | select employeenumber,samaccountname,description
$users_from_database = Import-Csv 'database_users.csv' | select employee number

O que acontece quando executamos esses dois arrays através do mesmo cenário que nossas strings? Absolutamente nada. Por quê?

A razão é porque você não pode dizer normalmente $object1 -eq $object2 porque os objetos são mais complexos do que uma simples string, booleano ou inteiro. Existem algumas outras circunstâncias em que isso não é o caso, mas tento criar o hábito de comparar propriedades de objetos; não objetos inteiros. Então, nesse caso, temos que fazer algo assim:

$ad_user[0].employeeNumber -eq $users_from_database[0].employeeNumber

Qual é a solução? Atualmente, tenho duas soluções. Lidar com milhares de objetos não é rápido, mas funciona. Gostaria de saber se mais alguém tem outras sugestões.

$ad_employee_numbers = $ad_users | % {$_.employeenumber}

## Criar um array de strings apenas com o número do funcionário do usuário do AD
$users_from_database | Where-Object -FilterScript { $ad_employee_numbers -contains $_.employeeNumber }

Podemos também usar Compare-Object, embora isso seja mais lento.

$ad_employee_numbers = $ad_users | ForEach-Object {$_.employeenumber}

## Criar um array de strings apenas com o número do funcionário do usuário AD
$database_user_employee_numbers = $users_from_database | ForEach-Object {$_.employeenumber}

## Criar um array de strings apenas com o número do funcionário do usuário do banco de dados
(Compare-Object $ad_employee_numbers $database_user_employee_numbers -IncludeEqual | Where-Object -FilterScript {$_.SideIndicator -eq '=='}).InputObject

Conclusão

Há muitas maneiras diferentes de usar o PowerShell para comparar arrays. Arrays podem ser complexos e entender completamente os objetos dentro deles ajudará bastante na comparação.

Source:
https://adamtheautomator.com/powershell-compare-arrays/