Сравнение массивов сделано легко с помощью PowerShell

Используя некоторые PowerShell-фокусы, вы легко можете сравнивать массивы различных объектов с помощью PowerShell. Существует много различных сценариев, в которых вы можете оказаться, поэтому давайте вникнем и посмотрим, каким образом мы можем использовать PowerShell для сравнения массивов.

Чтобы определить наилучший способ сравнения массивов, вам сначала нужно выяснить, какие типы элементов содержатся в обоих массивах.

  • Содержат ли оба массива одинаковые типы объектов?
  • Имеют ли оба массива одинаковое количество элементов?
  • Содержатся ли разные типы объектов в каждом массиве?

Вы должны знать ответ на каждый из этих вопросов, прежде чем точно сравнивать массивы. Давайте рассмотрим каждый сценарий.

Сравнение массивов строк

Один из самых простых способов сравнения массивов с помощью PowerShell – это когда у вас есть два массива, содержащих только строки. Когда у вас возникает такая ситуация, у вас есть несколько различных способов сравнения строк в массивах.

Использование операторов -Contains или -In

Оператор -contains в PowerShell позволяет вам проверять, содержится ли объект в коллекции. Оператор -contains изначально не понимает коллекции, но вы можете написать код, чтобы он выполнял вашу задачу.

Предположим, что у коллекции (массива) есть четыре строки, как показано ниже.

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

Оператор -contains работает, проверяя, содержится ли одна строка в этом массиве, например так:

$array -contains 'pink'

Когда коллекция слева содержит эту строку, PowerShell вернет True. В противном случае он вернет False.

PowerShell -contains Operator

Мы можем сравнивать массивы с помощью оператора -contains, читая каждую строку в массиве и проверяя, содержит ли другой массив эту строку.

Допустим, я хочу сравнить два массива, чтобы увидеть, какие строки из первого массива существуют во втором массиве.

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

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

Вы также можете использовать оператор -in, который идентичен оператору -contains, но с обратным синтаксисом. При использовании оператора -contains массив определяется слева. При использовании оператора -in массив определяется справа, как показано ниже:

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

Использование Where-Object

В качестве альтернативы вы также можете использовать командлет Where-Object для возврата всех строк из одного массива в другой, как показано ниже.

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

Использование командлета Compare-Object

Вы также можете использовать PowerShell для сравнения массивов с помощью командлета Compare-Object. Этот командлет принимает ссылочный объект и объект с различиями и возвращает индикатор стороны, указывающий, какие элементы находятся и не находятся в любом из массивов.

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

Ниже вы можете видеть, что командлет Compare-Object позволяет сравнивать оба массива одновременно. Если свойство SideIndicator равно =>, это означает, что возвращенное свойство InputObject находится в значении DifferenceObject и не находится в значении ReferenceObject, и наоборот для <= SideIndicator.

По умолчанию, Compare-Object возвращает различия. Вы также можете вернуть все строки в каждом массиве, которые присутствуют в обоих, используя параметр IncludeEqual.

Comparing arrays with Compare-Object

Сравнение массивов сложных объектов

Достаточно просто, верно? Теперь давайте добавим объекты в наше уравнение. Допустим, у нас есть поле в базе данных HR, и мы хотим заполнить этим полем описание в Active Directory. Прежде чем сделать это, у нас должен быть общий идентификатор. У меня в среде есть номер сотрудника как в базе данных HR, так и в пользовательском атрибуте Active Directory. Давайте попробуем это сравнить.

Сначала посмотрим, что произойдет, если мы попробуем наш предыдущий подход. Вот файл CSV, который мы используем.

CSV output

Вот как я получаю наши два набора данных.

$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

Что происходит, когда мы запускаем эти два массива через тот же сценарий, что и наши строки? Совершенно ничего. Почему?

Причина в том, что обычно нельзя сказать $object1 -eq $object2, потому что объекты более сложны, чем простая строка, булево значение или целое число. Есть некоторые другие обстоятельства, когда это не так, но я стараюсь привести привычку сравнивать свойства объектов; не целые объекты. Так что в этом случае нам нужно сделать что-то вроде этого:

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

Какое решение? В настоящее время у меня есть два варианта. При работе с тысячами объектов это не быстро, но это работает. Мне бы хотелось узнать, есть ли у кого-то еще какие-то предложения.

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

## Создайте массив строк только с табельным номером пользователя AD
$users_from_database | Where-Object -FilterScript { $ad_employee_numbers -contains $_.employeeNumber }

Мы также можем использовать Compare-Object, хотя это медленнее.

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

## Создайте массив строк только с табельными номерами пользователей AD
$database_user_employee_numbers = $users_from_database | ForEach-Object {$_.employeenumber}

## Создайте массив строк только с табельными номерами пользователей базы данных
(Compare-Object $ad_employee_numbers $database_user_employee_numbers -IncludeEqual | Where-Object -FilterScript {$_.SideIndicator -eq '=='}).InputObject

Вывод

Существует множество различных способов использования PowerShell для сравнения массивов. Массивы могут быть сложными, и глубокое понимание объектов внутри массивов значительно поможет вам их сравнивать.

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