Comparação de Arrays Facilitada com PowerShell

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

Para determinar a melhor maneira de comparar arrays, você deve primeiro descobrir quais tipos de elementos estão presentes em ambos os arrays.

  • Ambos os arrays contêm o mesmo tipo de objeto?
  • Ambos os arrays têm o mesmo número de elementos?
  • Há diferentes tipos de objetos em cada array?

Você deve saber a resposta para cada uma dessas perguntas antes de poder comparar arrays com precisão. Vamos abordar cada cenário.

Comparando Arrays de Strings

Uma das maneiras mais fáceis de comparar arrays com PowerShell é se você tiver dois arrays contendo apenas strings. Quando você se encontrar nessa situação, você tem algumas maneiras diferentes de comparar as strings nos arrays.

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 como desejar.

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

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

O operador -contains funciona verificando se uma única string está presente nesse array da seguinte forma:

$array -contains 'pink'

Quando a coleção à esquerda contém essa string, o PowerShell retornará True. Caso contrário, retornará False.

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 poderia 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. Usando 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 poderia 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 de lado 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 de InputObject retornado está no valor de DifferenceObject e não no valor de ReferenceObject, e vice-versa para o <= SideIndicator.

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, certo? Agora, vamos introduzir objetos. 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, vamos ver o que acontece se tentarmos nossa abordagem anterior. Aqui está o arquivo CSV que estamos usando.

CSV output

Aqui está como eu 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 pelo mesmo cenário que nossas strings? Absolutamente nada. Por quê?

O motivo é porque você normalmente não pode dizer $object1 -eq $object2 porque 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 ter o hábito de comparar propriedades de objetos; não objetos inteiros. Então, neste 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. Ao lidar com milhares de objetos, não é rápido, mas funciona. Gostaria de saber se mais alguém tem alguma outra sugestão.

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

## Criar um array de strings apenas com o número de 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 de 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 de 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 dos arrays ajudará muito na comparação.

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