Array-Vergleiche leicht gemacht mit PowerShell

Mit ein wenig PowerShell-Kung-Fu können Sie Arrays aller Arten von Objekten problemlos vergleichen. Es gibt viele verschiedene Szenarien, in denen Sie sich befinden können, also lassen Sie uns eintauchen und die Möglichkeiten erkunden, wie wir PowerShell verwenden können, um Arrays zu vergleichen.

Um die beste Methode zum Vergleichen von Arrays zu bestimmen, müssen Sie zunächst herausfinden, welche Arten von Elementen in beiden Arrays enthalten sind.

  • Enthalten beide Arrays denselben Typ von Objekten?
  • Haben beide Arrays dieselbe Anzahl von Elementen?
  • Gibt es unterschiedliche Objekttypen in jedem Array?

Sie müssen die Antwort auf jede dieser Fragen kennen, bevor Sie Arrays genau vergleichen können. Lassen Sie uns jedes Szenario behandeln.

Vergleich von Arrays von Strings

Eine der einfachsten Möglichkeiten, Arrays mit PowerShell zu vergleichen, besteht darin, wenn Sie zwei Arrays haben, die nur Zeichenfolgen enthalten. Wenn Sie sich in dieser Position befinden, haben Sie verschiedene Möglichkeiten, Zeichenfolgen in den Arrays zu vergleichen.

Verwendung der Operatoren -Contains oder -In

Der -Contains-Operator ist ein PowerShell-Operator, mit dem Sie überprüfen können, ob ein Objekt in einer Sammlung enthalten ist. Der -Contains-Operator versteht Sammlungen von Natur aus nicht, aber Sie können Code erstellen, um ihn entsprechend zu verwenden.

Angenommen, eine Sammlung (Array) enthält vier Zeichenfolgen wie unten dargestellt.

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

Der -Contains-Operator funktioniert, indem er überprüft, ob eine einzelne Zeichenfolge in diesem Array enthalten ist, wie folgt:

$array -contains 'pink'

Wenn die Sammlung auf der linken Seite diese Zeichenfolge enthält, gibt PowerShell True zurück. Andernfalls gibt es False zurück.

PowerShell -contains Operator

Wir können Arrays mit dem -contains-Operator vergleichen, indem wir jeden String in einem Array lesen und überprüfen, ob das andere Array diesen String enthält.

Angenommen, ich möchte zwei Arrays vergleichen, um zu sehen, welche Strings im ersten Array im zweiten Array existieren.

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

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

Sie könnten alternativ den -in-Operator verwenden, der identisch mit dem -contains-Operator ist, jedoch eine umgekehrte Syntax aufweist. Bei Verwendung des -contains-Operators wird das Array auf der linken Seite definiert. Bei Verwendung des -in-Operators wird das Array auf der rechten Seite definiert, wie unten gezeigt:

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

Mit Where-Object

Alternativ könnten Sie auch das Where-Object-Cmdlet verwenden, um alle Strings in einem Array im anderen Array zurückzugeben, wie unten gezeigt.

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

Mit dem Compare-Object-Cmdlet

Sie können auch PowerShell verwenden, um Arrays mit dem Compare-Object-Cmdlet zu vergleichen. Dieses Cmdlet nimmt ein Referenzobjekt und ein Differenzobjekt entgegen und gibt einen Seitensymbolindikator zurück, der anzeigt, welche Elemente in beiden Arrays vorhanden sind und welche nicht.

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

Wie unten gezeigt, ermöglicht es das Compare-Object-Cmdlet, beide Arrays gleichzeitig zu vergleichen. Wenn die Eigenschaft SideIndicator => ist, bedeutet dies, dass das zurückgegebene InputObject-Objekt im Wert DifferenceObject enthalten ist und nicht im Wert ReferenceObject und umgekehrt für den <= SideIndicator.

Standardmäßig gibt Compare-Object Unterschiede zurück. Sie können auch alle Zeichenfolgen in jedem Array zurückgeben, die in beiden enthalten sind, indem Sie den Parameter IncludeEqual verwenden.

Comparing arrays with Compare-Object

Vergleich von Arrays komplexer Objekte

Ganz einfach, oder? Jetzt bringen wir Objekte ins Spiel. Nehmen wir an, wir haben ein Feld in dieser HR-Datenbank und möchten dies in das Beschreibungsfeld des Active Directory übertragen. Bevor wir dies tun, müssen wir zunächst einen gemeinsamen Identifikator haben. In meiner Umgebung gibt es eine Mitarbeiternummer sowohl in der HR-Datenbank als auch im benutzerdefinierten Active Directory-Attribut. Versuchen wir also, dies abzugleichen.

Zunächst sehen wir, was passiert, wenn wir unseren vorherigen Ansatz versuchen. Hier ist die CSV-Datei, die wir verwenden.

CSV output

So erhalte ich unsere beiden Datensätze.

$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

Was passiert, wenn wir diese beiden Arrays durch das gleiche Szenario wie unsere Zeichenfolgen führen? Absolut nichts. Warum?

Der Grund dafür ist, dass Sie normalerweise nicht sagen können $object1 -eq $object2, weil Objekte komplexer sind als eine einfache Zeichenfolge, ein Boolescher Wert oder eine ganze Zahl. Es gibt einige andere Umstände, in denen dies nicht der Fall ist, aber ich versuche es mir zur Gewohnheit zu machen, die Eigenschaften von Objekten zu vergleichen, nicht ganze Objekte. In diesem Fall müssen wir also etwas wie dies tun:

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

Was ist die Lösung? Derzeit habe ich zwei Lösungen. Bei der Arbeit mit Tausenden von Objekten ist es nicht schnell, aber es funktioniert. Ich würde gerne wissen, ob jemand andere Vorschläge hat.

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

## Erstellen Sie ein Array von Zeichenfolgen, die nur die Mitarbeiternummer des AD-Benutzers enthalten
$users_from_database | Where-Object -FilterScript { $ad_employee_numbers -contains $_.employeeNumber }

Wir können auch Compare-Object verwenden, obwohl dies langsamer ist.

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

## Erstellen Sie ein Array von Zeichenfolgen, die nur die Mitarbeiternummer des AD-Benutzers enthalten
$database_user_employee_numbers = $users_from_database | ForEach-Object {$_.employeenumber}

## Erstellen Sie ein Array von Zeichenfolgen, die nur die Mitarbeiternummer des Datenbankbenutzers enthalten
(Compare-Object $ad_employee_numbers $database_user_employee_numbers -IncludeEqual | Where-Object -FilterScript {$_.SideIndicator -eq '=='}).InputObject

Schlussfolgerung

Es gibt viele verschiedene Möglichkeiten, PowerShell zum Vergleichen von Arrays zu verwenden. Arrays können komplex sein und ein gründliches Verständnis der Objekte in den Arrays wird Ihnen bei ihrem Vergleich sehr helfen.

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