PowerShell Dateigröße vergleichen

D0c_cR4Zy

Lieutenant
Registriert
Feb. 2007
Beiträge
658
Moin,

ich vergleiche mit folgendem Snippet die Dateigröße von 2 Dateien:
Code:
(get-childitem "Path\File" | select-object length) -eq (get-childitem "Path\File" | select-object length)

Als Ergebnis erhalte ich FALSE

Wenn ich die beiden Abfragen aber einzeln laufen lasse, erhalte ich bei beiden das Ergebnis 9163754.

Kann mir jemand erklären warum?

Hintergrund:
Ich möchte eine kleine Anwendung schreiben, mit welcher ich von 2 Verzeichnissen alle Dateien vergleiche. Wenn die Datei in beiden Verzeichnisse vorhanden ist UND den gleichen Namen hat UND die gleiche Dateigröße dann soll er die Datei in Verzeichnis 2 löschen.
Ich beginne also gerade erst ;)

Was ich ebenfalls schon habe ist folgendes:
Code:
Compare (gci "Pfad") (gci "Pfad") -IncludeEqual -ExcludeDifferent
Hiermit kann ich die Dateien identifizieren welche in Pfad 1 und Pfad 2 enthalten sind. Daraus müsste ich nun also eine "Ergebnisliste" erstellen und diese dann in den "Größenabgleich" schicken. So zumindest aktuell die Idee!

Normalerweise erstelle ich für Dateioperationen immer mal wieder Batch Dateien, PowerShell wurde mir als "besseres" Tool für diese Aufgabe empfohlen. Ich nutze die beschriebene Anforderung um mich an das Thema mal ranzutasten und erste Erfahrungen zu sammeln.

CYA_D0c
 
Zuletzt bearbeitet:
Tatsächlich ist PowerShell das bessere Tool als die altehrwürdige Batch (nicht besonders verwunderlich ;)).
Bei PowerShell arbeitest du mit Objekten. Wenn du zwei verschiedene Objekte vergleichst sind sie natürlich nicht identisch (das machst du bei deinem ersten Beispiel).

https://docs.microsoft.com/en-us/po...ell.utility/select-object?view=powershell-5.1

Probier mal diese beiden Zeilen aus und du wirst den Unterschied zwischen den Befehlen sehen.
CustomObject:
Code:
(Get-Item -Path $Path | Select-Object Length).gettype()

Int:
Code:
(Get-Item -Path $Path | Select-Object -ExpandProperty Length).gettype()

Was du auch machen kannst:
Code:
(Get-Item -Path $Path).Length

In deinem Fall würde also reichen:
Code:
(Get-Item "Path\File").Length -eq (Get-Item "Path\File").Length
 
D0c_cR4Zy schrieb:
Wenn die Datei in beiden Verzeichnisse vorhanden ist UND den gleichen Namen hat UND die gleiche Dateigröße dann
das ist eigentlich kein valider Test auf Duplikate. Selbst mit einem kryptographischen Hash wie MD5 haettest du keine 100% Garantie dass die Bytes in der richtigen Reihenfolge mit den gleichen Werten vorliegen. Trotzdem wuerde ich eher noch MD5 oder was anderes mit als Vergleich nehmen
 
  • Gefällt mir
Reaktionen: DubZ
PS lädt ja zum Einzeiler ein. Das ist auch meistens elegant... aber nicht immer.

Sauberer:
PowerShell:
[System.IO.FileInfo] $fileA = Get-Item -Path path/to/fileA
[System.IO.FileInfo] $fileB = Get-Item -Path path/to/fileB

$fileA.length -eq $fileB.length

@abcddcba vielleicht nicht 100%ig, aber definitiv sicher genug. MD5 ist immer noch kollisionsresistent genug gegen Zufälle. Es haben nicht einfach so zwei Dateien denselben MD5 Hash. Dazu muß man gezielt, und insbesondere in Abhängigkeit des Inputs selbst, Inputblöcke manipulieren. Zufällig passiert sowas nicht.

Natürlich sei die Frage aber zugelassen, wenn man MD5 nehmen kann, warum man nicht gleich auf SHA256 setzt.

Desweiteren gibts bei Windows einen Dateiindex. Das ist das eigentliche Datenobjekt im Dateisystem. Ist der gleich für zwei Dateien D1 und D2, dann hat man Hardlinks. (fsutil hardlink... liefert Entsprechendes auch).

Außerdem bedenken, daß es in NTFS auch Softlinks gibt. Wenn eine der beiden überprüften Dateien ein Softlink ist, muß unbedingt sichergestellt sein, daß wenn "gleich" rauskommt, (a) hinterher der Softlink gelöscht wird... oder (b) beim Vergleich mit Softlinks per definitionem immer $false geliefert wird.

Anderenfalls löscht man mit Pech das Ziel des Softlinks und dann ist die Datei ersatzlos hinüber.
 
  • Gefällt mir
Reaktionen: abcddcba
RalphS schrieb:
vielleicht nicht 100%ig, aber definitiv sicher genug. MD5 ist immer noch kollisionsresistent genug gegen Zufälle. Es haben nicht einfach so zwei Dateien denselben MD5 Hash. Dazu muß man gezielt, und insbesondere in Abhängigkeit des Inputs selbst, Inputblöcke manipulieren. Zufällig passiert sowas nicht.
Ja, das weiss ich, wollte nur formal korrekt sein, ich weiss doch wie pedantisch und penibel Informatiker wie wir nun einmal sind.
 
Moin,

sehr schöner Thread, danke dafür!

Hab zwischendurch mich noch einmal ein wenig umgesehen und was ausprobiert und habe denke ich meine Lösung:
Code:
$one = Get-ChildItem "Path01"
$two = Get-ChildItem "Path02"

$matches = (Compare-Object -ReferenceObject $one  -DifferenceObject $two -Property Name,Length -ExcludeDifferent -IncludeEqual)

foreach ($file in $matches)
{
    Remove-Item "Path02\$($file.Name)"
}

@RalphS
Ich denke das geht in die Richtung von deiner Lösung :D

Was sagt ihr dazu?

CYA_D0c
 
Ich wäre vorsichtig damit, insbesondere, da wir hier -- wie bereits eingedeutet -- mit Objekten arbeiten.

In der Objektorientierung gibt es, konfuserweise, verschiedene Gleichheiten. Da wäre zunächst die referentielle Gleichheit (Identität) und dann die semantische Gleichheit (Identität).

Ein Beispiel.

DateiA mit Inhalt ABC + Enter.
DateiB mit Inhalt ABC + Enter.

Das sind zwei Dateien. Haben nichts miteinander zu tun, außer daß in beiden zufällig dasselbe drinsteht und somit beide identische Filehashes haben.

Nur ist $dateiA.equals($dateiB) $false. Es sind zwei verschiedene Dateien. Eben so, wie zwei Fahrräder, die identisch aussehen, trotzdem zwei Fahrräder sind und nicht nur eines.

Daher kann an der Stelle wirklich nur KISS empfohlen werden. Wenn sich die semantische Gleichheit von A und B aus der Gleichheit bestimmter Eigenschaften bestimmt, dann wäre der nächste Schritt eine Funktion Compare-File anzulegen und die $true liefert, wenn alle benannten Eigenschaften übereinstimmen bzw. $false, wenn (nur eine) abweicht.

abcddcba schrieb:
Ja, das weiss ich, wollte nur formal korrekt sein, ich weiss doch wie pedantisch und penibel Informatiker wie wir nun einmal sind.

Patience, young grasshopper. :daumen: Über die Zeit läßt das auch bei Informatikern nach. Zumindest... die Überpedanterie? Wie man's auch nennen mag. Kontext ist relevant; gibt's keinen geht es meistens schief.
Aber ich weiß wovon Du sprichst, auch von mir selber. 😊 Bin ehrlich gesagt ganz froh drüber, davon zumindest ein bißchen wegzusein. Plus wie man ja hier sieht... so schnell kann man gar nicht gucken kommt der an mit "aber gleich ist nicht dasselbe wie gleich" und da kommt die Pedanterie ganz schnell doch wieder rum, weil es an der Stelle einfach wichtig ist (oder zu sein scheint). Ich mein, wer kommt auf die Idee, daß $a -eq $b einerseits und $a.Equals($b) andererseits nicht dasselbe sein könnte?
 
Zuletzt bearbeitet von einem Moderator:
Moin,

@RalphS ja ich habe deine Anmerkungen verstanden, für meinen aktuellen Fall prüft es schon mehr als vorher der Mensch geprüft hat und das viel schneller. Ich werde das Thema trotzdem mal eine Zeit lang beobachten und dann entscheiden ob ich es voll automatisiere.

Zu deinen Ausführungen:
Was meinst du genau mit
In der Objektorientierung gibt es, konfuserweise, verschiedene Gleichheiten. Da wäre zunächst die referentielle Gleichheit (Identität) und dann die semantische Gleichheit (Identität).
Du nennst beides Identität? Ist das korrekt? Wird da nicht noch einmal unterschieden in der Begrifflichkeit?

Mich wundert das die Hashes in deinem Beispiel gleich sind, muss mich vllt mal ein wenig mehr in das Thema einlesen.

Aktuell würde ich erwarten.
FileA erstellt am 13.03 durch Applikation FileB erstellt am 14.03 durch User - gleicher Inhalt
-> Hier würde ich False erwarten

FileA erstellt am 13.03 durch Applikation FileB erstellt am 14.03 durch Applikation mit Systemdatum 13.03 - gleicher Inhalt
-> Hier würde ich True erwarten

Bin wirklich nicht drin im Thema Hashes, habe ich bisher nicht benötigt, mir fallen allerdings langsam Szenarien ein was ich damit so anstellen könnte ;)

CYA_D0c
 
Hashing (im kryptographischen Sinne) ist einfach eine Methode, um einer Nachricht eine eindeutige Kennung zuzuordnen, ohne jedoch diese umkehrbar identifizierbar zu machen.

In dem Fall ist die Nachricht der Inhalt der Datei (nicht die Datei als Container des Inhalts). Wenn Du Dateien hast A und B, und eine (gemeinsame) Hashfunktion liefert für beide Dateien denselben Wert, dann ist der Inhalt dieser Dateien praktisch zuverlässig identisch. Kollisionen sind möglich - Hashfunktionen haben nur begrenzt viele Ergebnisse, die sie darstellen können -- können aber zumindest im Normalfall ausgeschlossen werden. Empfehlenswert sind dieser Tage Funktionen mit "längeren" Ergebnissen - MD5 gibt 32bits, SHA256 derer 8x so viele und entsprechend ist letzteres signifikant zuverlässiger.

Ich hab an der Stelle beides "Identität" genannt zur Veranschaulichung und um auf das Problem hinzuweisen. Das eine ist Wertgleichheit. Das andere ist referentielle Identität. Wie man es nennt ist egal, wichtig ist, daß man den Unterschied versteht.
A Wert: zwei (verschiedene) Daten haben exakt denselben Wert, zB zwei gleiche Fahrräder.
B Referentiell: zwei Verweise aufs selbe Datum, zB zwei Fotos desselben Fahrrads.

B impliziert immer A, da Selbstidentität angenommen werden darf (mit wenigen Ausnahmen).

Ich bin grad nicht sicher, was Du mit Deinen Beispielen ausdrücken möchtest: ist dieses Verhalten das, was Du gerne haben willst, oder das, was Du denkst, daß die Hashfunktion das so liefert?

Da die HF immer nur Inhalte berücksichtigt, ist ihr Ergebnis auch wirklich nur vom Inhalt abhängig. Dateinamen und alle anderen Metainformationen wie das Erstellungsdatum bleiben außen vor und "hash datei" ist dasselbe wie "echo $dateinhalt | hash".

Wenn Dateiinformationen berücksichtigt werden sollen, dann müssen sie zusätzlich geprüft werden. Diese kann man dazu durchaus auch in einen String schreiben und dann dort die gewählte HF drüberlaufen lassen. Man muß dann aber ein definiertes Schema verwenden und beibehalten - jedes einzelne Byte, was verschieden ist, sorgt bereits für ein anderes Ergebnis der Hashfunktion, also kann man nicht mit "Datum: xyz" === "Datum ist xyz" kommen, was für beliebiges Datum immer voneinander verschieden wäre.
 
Moin,

Danke für die detailierte Ausführung. Ich werde ich mla näher mit dem Thema beschäftigen und melde mich ggf. wieder ;)

THX!!!

CYA_D0c
 
Zurück
Oben