ddoollyy
Goto Top

Einen Hash über Powershell erstellen für mehrere Dateien

Hey an Alle,

Ich habe zurzeit die Aufgabe, aus Archivierungsgründen eine Hash über meine Powerschell zu erstellen, die alle Dateien in einem Ordner in insgesamt einer Prüfsumme sammelt. Ich habe bisschen gegoogelt, gefunden habe ich bis jetzt nur wie ich mit "Get-FileHash" eine Hash für jeweils eine Datei erzeuge. Es bringt mir leider auch nichts, nur die Prüfsumme von dem Ordner zu erstellen, es sollen am besten alle Dateien in diesem Ordner gelistet sein, da mir gesagt wurde, dass die Prüfsumme nicht mehr stimmen wird beim Vergleich. Gibt es einen Befehl, wo ich, vielleicht mit Get-FileHash, alle Dateien aufliste und die Shell mir dann eine einzige Hash erzeugt?


Liebe Grüße,
Robin face-smile

Content-Key: 7029464841

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

Printed on: May 23, 2024 at 21:05 o'clock

Member: Kraemer
Kraemer May 05, 2023 updated at 13:42:14 (UTC)
Goto Top
Moin,

du solltest dir unbedingt mal die Beschreibung von Get-FileHash ansehen. Ganz wichtig dabei ist die Informationen wovon eigentlich ein Hash erstellt wird.
Member: emeriks
emeriks May 05, 2023 at 14:01:16 (UTC)
Goto Top
Hi,
von jeder Datei eines Verzeichnis einen Hash erzeugen mit Get-Hash. Diese Hash alle in eine Datei schreiben lassen.
Von dieser einen Datei einen Hash erstellen. --> Das ist dann Dein Hash pro verzeichnis.

E.
Member: DerWoWusste
Solution DerWoWusste May 05, 2023 at 14:05:56 (UTC)
Goto Top
7zip macht das ordentlich:

"c:\Program Files\7-Zip\7z.exe" h -scrcsha256 "c:\ordner"  
Mitglied: 7010350221
Solution 7010350221 May 05, 2023 updated at 14:15:39 (UTC)
Goto Top
$allhashes = (Get-ChildItem "E:\Ordner" -File -Recurse | Get-FileHash -Algorithm SHA256).Hash -join ''  
$folderHash = [System.BitConverter]::ToString([System.Security.Cryptography.HashAlgorithm]::Create("SHA256").ComputeHash([System.Text.Encoding]::ASCII.GetBytes($allhashes))).replace('-','')  

Gruß pille
Member: Kraemer
Kraemer May 05, 2023 at 14:10:54 (UTC)
Goto Top
Zitat von @DerWoWusste:

7zip macht das ordentlich:

"c:\Program Files\7-Zip\7z.exe" h -scrcsha256 "c:\ordner"  

man könnte auch die Ausgabe von

Get-FileHash c:\temp\*

ein eine Datei schreiben
Mitglied: 3063370895
Solution 3063370895 May 05, 2023 updated at 14:19:46 (UTC)
Goto Top
$folder = "D:\tmp\"  

$tempFile = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
Get-ChildItem -Recurse -File $folder | Get-FileHash | Select-Object Hash | Set-Content $tempFile
$folderHash = Get-FileHash $tempFile
Remove-Item $tempFile -Force

-Thomas
Member: Kraemer
Solution Kraemer May 05, 2023 updated at 14:18:50 (UTC)
Goto Top
Zitat von @3063370895:

oder

$stringAsStream = [System.IO.MemoryStream]::new()
$writer = [System.IO.StreamWriter]::new($stringAsStream)
$writer.write((Get-FileHash c:\temp\*))
$writer.Flush()
$stringAsStream.Position = 0
Get-FileHash -InputStream $stringAsStream | Select-Object Hash

bleibt aber immer noch die Frage offen, welche Intigrität eigentlich wie geprüft werden soll...
Mitglied: 7010350221
Solution 7010350221 May 05, 2023 updated at 14:35:00 (UTC)
Goto Top
Schnellere Hashes würde auch ein CRC32 Hash liefern, gerade bei großen Dateien spart das einiges an Zeit, das reicht manchmal schon.
Add-Type '  
using System;
using System.IO;

public static class CRC32{
    public static string ComputeHash(Stream stream){
        uint[] ChecksumTable = new uint[0x100];
        uint poly = 0xEDB88320;
        for (uint index = 0; index < 0x100; ++index){
            uint item = index;
            for (int bit = 0; bit < 8; ++bit)
                item = ((item & 1) != 0) ? (poly ^ (item >> 1)) : (item >> 1);
            ChecksumTable[index] = item;
        }
        uint result = 0xFFFFFFFF;
        int current;
        while ((current = stream.ReadByte()) != -1)
            result = ChecksumTable[(result & 0xFF) ^ (byte)current] ^ (result >> 8);

        byte[] hash = BitConverter.GetBytes(~result);
        Array.Reverse(hash);
        return BitConverter.ToString(hash).Replace("-","");  
    }
    public static string ComputeHash(byte[] data){
        using (MemoryStream stream = new MemoryStream(data))
            return ComputeHash(stream);
    }
    public static string ComputeHash (string file){
        using (FileStream stream = new FileStream(file,FileMode.Open))
            return ComputeHash(stream);
    }
}'  
$hashes = foreach($file in Get-ChildItem "E:\Ordner" -File -Recurse){[CRC32]::ComputeHash($file.Fullname)}  
$folderHash = [System.BitConverter]::ToString([System.Security.Cryptography.SHA256]::Create().ComputeHash([System.Text.Encoding]::ASCII.GetBytes($hashes))).replace('-','')  
Member: Kraemer
Kraemer May 05, 2023 at 14:37:03 (UTC)
Goto Top
Ist das nicht herrlich, wieviele Wege es gibt, ein nicht genauer definiertes Problem zu lösen face-big-smile
Mitglied: 3063370895
3063370895 May 05, 2023 updated at 14:42:00 (UTC)
Goto Top
Zitat von @pille6:

Schnellere Hashes würde auch ein CRC32 Hash liefern, gerade bei großen Dateien spart das einiges an Zeit, das reicht manchmal schon.
Ist bei mir um Faktor 5 langsamer als Get-Filehash

-Thomas
Mitglied: 7010350221
7010350221 May 05, 2023 updated at 14:49:41 (UTC)
Goto Top
Zitat von @3063370895:
Ist bei mir um Faktor 5 langsamer als Get-Filehash
Wiederhol das mal mit größeren Dateien und SHA256 face-wink Dann wirst du den Unterschied sehen ...

Hier ein Vergleich beider Methoden eines Verzeichnisses rekursiv mit 2000 Dateien im RAM, erste Zeit CRC32, zweite Zeit Get-FileHash
CRC32  = 1,1185974s
Get-FileHash = 2,629939s
Mitglied: 3063370895
3063370895 May 05, 2023 updated at 15:04:15 (UTC)
Goto Top
Hier über einen 1,3 GB Ordner mit Videos:
2023-05-05 16_52_09-untitled-2.ps1 - visual studio code

Hier mit PS 5.1, damit keiner sagt es liegt an PS7 face-smile
2023-05-05 16_53_52-untitled-2.ps1 - visual studio code

Nicht ganz Faktor 5, aber 3-4

Hier der ganze Code:
$folder = "D:\tmp"  
 
$sha256 = Measure-Command -Expression {
    $tempFile = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
    Get-ChildItem -Recurse -File $folder | Get-FileHash -Algorithm SHA256| Select-Object Hash | Set-Content $tempFile
    $folderHashsha256 = Get-FileHash -Algorithm SHA256 $tempFile 
    remove-item $tempFile -force
 
} | select -expandproperty totalseconds
 
 
$crc32 = Measure-Command -Expression {
    Add-Type '  
using System;
using System.IO;
 
public static class CRC32{
    public static string ComputeHash(Stream stream){
        uint[] ChecksumTable = new uint[0x100];
        uint poly = 0xEDB88320;
        for (uint index = 0; index < 0x100; ++index){
            uint item = index;
            for (int bit = 0; bit < 8; ++bit)
                item = ((item & 1) != 0) ? (poly ^ (item >> 1)) : (item >> 1);
            ChecksumTable[index] = item;
        }
        uint result = 0xFFFFFFFF;
        int current;
        while ((current = stream.ReadByte()) != -1)
            result = ChecksumTable[(result & 0xFF) ^ (byte)current] ^ (result >> 8);
 
        byte[] hash = BitConverter.GetBytes(~result);
        Array.Reverse(hash);
        return BitConverter.ToString(hash).Replace("-","");  
    }
    public static string ComputeHash(byte[] data){
        using (MemoryStream stream = new MemoryStream(data))
            return ComputeHash(stream);
    }
    public static string ComputeHash (string file){
        using (FileStream stream = new FileStream(file,FileMode.Open))
            return ComputeHash(stream);
    }
}'  
    $hashes = foreach ($file in Get-ChildItem $folder -File -Recurse) { [CRC32]::ComputeHash($file.Fullname) }
    $folderHashcrc32 = [System.BitConverter]::ToString([System.Security.Cryptography.SHA256]::Create().ComputeHash([System.Text.Encoding]::ASCII.GetBytes($hashes))).replace('-', '')  
} | select -expandproperty totalseconds
 
[PSCustomObject]@{
    "SHA256Time" = $sha256  
    "CRC32Time"  = $crc32  
}

Ach nochwas: Ich glaube nicht, dass OP die selbe Datei im RAM 2000 mal hashen will face-smile

-Thomas