使用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 cmdlet来返回另一个数组中的一个数组中的所有字符串,如下所示。

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

使用Compare-Object Cmdlet

您还可以使用PowerShell来使用Compare-Object cmdlet来比较数组。此cmdlet接受一个参考对象和一个差异对象,并返回一个侧指示器,指示哪些元素在任一数组中而不在其中。

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

您可以看到Compare-Object cmdlet允许您同时比较两个数组。如果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/