derhoeppi
Goto Top

PowerShell zwei Array mit unterschiedlichem Inhalt vergleichen

Hallo,

folgende Aufgabe muss ich in einem Skript zur Administration eines Storagesystems lösen. Mit einem Befehl lese ich die im Storagesystem konfigurierten Hosts in ein Array $Array_Hosts. Im folgenden erstelle ich ein weiteres Array $Array_MapHosts, welches andere Spalten aufweist. Jedoch gibt es in beiden Arrays Informationen die sich verknüpfen lassen. So gibt es im $Array_Hosts die Spalten ID und Name, die im Array $Array_MapHosts host_id und host_name heißen. Eine dieser beiden Spalten muss ich vergleichen und die Hosts die die Differenz bilden in einer Listbox ausgeben.

Mit dem Befehl Compare-Object kann ich scheinbar nur eindimensionale Arrays vergleichen. Dazu habe ich viele Beispiele gefunden - habe es aber nicht auf meinen Anwendungsfall anpassen können bzw. es gab keinen Output.

Kann mir jemand einen Ansatz nennen, so dass ich es weiter versuchen kann?

Gruß
derhoeppi

Content-Key: 267263

Url: https://administrator.de/contentid/267263

Printed on: April 19, 2024 at 18:04 o'clock

Mitglied: 114757
114757 Mar 24, 2015 updated at 14:33:59 (UTC)
Goto Top
Moin,
vergleiche nicht die kompletten Arrays sondern nur die jeweiligen Spalten der Arrays.
D.h. also das du im Compare-CMDLet als Reference-Object $Array_Hosts.ID verwendest und als Difference-Object $Array_MapHosts.host_id nimmst, feddich.

Beispiel:
Set-StrictMode -Version 3

# Für das Beispiel Daten erzeugen ------------------------------
$arr1 = @()
$arr2 = @()

$arr1 += [pscustomobject] @{"ID"="100";"Name"="Sepp Meier"}  
$arr1 += [pscustomobject] @{"ID"="101";"Name"="Max Muster"}  
$arr1 += [pscustomobject] @{"ID"="102";"Name"="Henriette Musterfrau"}  

$arr2 += [pscustomobject] @{"host_id"="100";"host_name"="Sepp Meier"}  
$arr2 += [pscustomobject] @{"host_id"="101";"host_name"="Max Muster"}  
$arr2 += [pscustomobject] @{"host_id"="102";"host_name"="Henriette Musterfrau"}  
$arr2 += [pscustomobject] @{"host_id"="103";"host_name"="Florian Zusatz"}  
# --------------------------------------------------------
# Vergleich
compare -ReferenceObject $arr1.id -DifferenceObject $arr2.host_id
Gruß jodel32
Member: derhoeppi
derhoeppi Mar 25, 2015 at 06:16:44 (UTC)
Goto Top
Hallo Jodel32,

wie ich sehe, war mein Versuch mit Compare-object gar nicht falsch. Ich habe nur die Parameter ReferenceObject und DifferenceObject weggelassen. Zusätzlich habe ich in der nachgelagerten foreach Schleife einen Fehler bei der Ausgabe gehabt. Der Fehler kommt zu stande, weil ich mit dem Vergleich der ID wiederum Rückschlüsse auf den Namen ziehen möchten, die dann in einer ListBox ausgegeben werden.

Wenn ich es in deinem Beispiel fortsetzte, dann habe ich darunter folgenden Code stehen:
$Difference = compare -ReferenceObject $arr1.id -DifferenceObject $arr2.host_id
foreach ($Server in $Difference){
$Hosts = $arr2 | ?{_.host.id -eq $Difference} | Select -expand name
$ListBox.Items.Add($Hosts)
}

Wenn ich mir nur $Difference in die Listbox schreiben lasse, erhalte ich die Host_id 's. Wenn ich aber die Verknüpfung herstellen möchte, bleibt die ListBox leer.

Gruß
derhoeppi
Mitglied: 114757
114757 Mar 25, 2015 updated at 07:56:27 (UTC)
Goto Top
Da ist ja auch alles durcheinander gewürfelt und lauter Flüchtigkeitsfehler drin....schau's die noch mal genau an.

min. PS 3.0//
$Difference = compare -ReferenceObject $arr1.id -DifferenceObject $arr2.host_id -passthru
$hosts = $arr2 | ?{$_.host_id -in $Difference} | Select -expand host_name
$ListBox.Items.Add($hosts)

Du machst immer den Fehler und schaust dir die Ausgabe der jeweiligen Befehle und deren Eigenschaften nicht exakt an.
Powerhell ist in dem Sinne Quasi schon eine Programmiersprache mit Objekten, Eigenschaften, etc. d.h. man muss schon mal schauen wie die jeweilige Ausgabe strukturiert ist. Dazu sind die CMDLets Get-Member, Format-List * etc. unerlässlich.
Einfach irgendein Objekt an ein anderes zu übergeben ohne das man weiß das diese zueinander kompatibel sind kann immer nur schief gehen !!

Gruß jodel32
Member: derhoeppi
derhoeppi Mar 25, 2015 at 08:09:47 (UTC)
Goto Top
Hallo Jodel32,

kannst du mir zum Verständnis noch mitteilen wofür der Parameter -passthru im compare cmdlet dient?
Mitglied: 114757
114757 Mar 25, 2015 updated at 11:21:28 (UTC)
Goto Top
Zitat von @derhoeppi:
kannst du mir zum Verständnis noch mitteilen wofür der Parameter -passthru im compare cmdlet dient?
Der gibt die ursprünglichen Objekte an die Pipe weiter, was ohne nicht der Fall ist. Schau dir die Ausgabe einfach mal mit und ohne Parameter an, dann siehst du den Unterschied face-wink

Was du natürlich beachten musst ist das fehlende Objekte auf beiden Seiten aufgelistet werden! Wenn du das nicht willst und nur eine Seite betrachten willst musst du den SideIndicator auswerten und so die Ausgabe filtern.
Bspw. so:
$Difference = compare -ReferenceObject $arr1.id -DifferenceObject $arr2.host_id  | ?{$_.SideIndicator -eq "=>"} | select -Expand InputObject  
Member: derhoeppi
derhoeppi Mar 26, 2015 at 06:46:59 (UTC)
Goto Top
Guten Morgen Jodel32,

die Differenz von beiden Arrays ist schon in Ordnung, weil die Differenz nicht mehr Einträge haben kann als die Referenz hergibt. Der SideIndicator ist deshalb nicht notwendig.

Heute morgen bin ich auf ein Problem gestoßen, dass eigentlich keins ist.

$Difference = compare -ReferenceObject $arr1.id -DifferenceObject $arr2.host_id -passthru 

Heute morgen war zum Test der Funktion das DifferenceObject leer, so dass nur die ReferenceObject einen Eintrag vorwies. Es kam zu einem Fehler, weil eben das DifferenceObject leer war. Um das Abzufangen würde ich jetzt eine eine if-else Bedingung vorstellen, die prüft, ob die Arrays leer sind und dementsprechend aggieren.

Gruß
derhoeppi
Mitglied: 114757
114757 Mar 26, 2015 at 07:35:01 (UTC)
Goto Top
Zitat von @derhoeppi:
Um das Abzufangen würde ich jetzt eine eine if-else Bedingung vorstellen, die prüft, ob die Arrays leer sind und dementsprechend aggieren.
und warum tust du das nicht ? Keinen Plan ?
if ($arr1 -and $arr2){
  # Compare .........
}else{
   # eins oder beide Arrays leer
}