使用 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/