So erhalten Sie eine MD5-Prüfsumme in PowerShell

178

Ich möchte eine MD5- Prüfsumme für einige Inhalte berechnen . Wie mache ich das in PowerShell?

Luke101
quelle
3
Was ist "etwas Inhalt"? eine Datei? Zeichenfolge?
vcsjones

Antworten:

325

Wenn der Inhalt eine Zeichenfolge ist:

$someString = "Hello, World!"
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$utf8 = New-Object -TypeName System.Text.UTF8Encoding
$hash = [System.BitConverter]::ToString($md5.ComputeHash($utf8.GetBytes($someString)))

Wenn der Inhalt eine Datei ist:

$someFilePath = "C:\foo.txt"
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($someFilePath)))

Ab PowerShell Version 4 ist dies mit dem Get-FileHashCmdlet für Dateien sofort möglich:

Get-FileHash <filepath> -Algorithm MD5

Dies ist sicherlich vorzuziehen, da dadurch die Probleme vermieden werden, die die erste Lösung bietet, wie in den Kommentaren angegeben (verwendet einen Stream, schließt ihn und unterstützt große Dateien).

vcsjones
quelle
12
Exception calling "ReadAllBytes" with "1" argument(s): "The file is too long. This operation is currently limited to supporting files less than 2 gigabytes in size."Als Linux-Neuling bei Powershell ärgere ich mich sehr über die Schwierigkeiten, die ich habe, wenn ich eine MD5-Summe bekomme, die einfach md5sum file.extunter Linux wäre.
StockB
Die Antwort von @StockB Keith unten wird wahrscheinlich besser damit umgehen. Ich stimme zu, es gibt einige Mängel bei Powershell.
vcsjones
5
Ich habe Vanilla PowerShell ohne Erweiterungen installiert, daher habe ich einen Befehlszeilen-md5sum-Klon heruntergeladen, der hervorragend funktioniert. Ich möchte Microsofts Sachen mögen, aber ich kann es einfach nicht.
StockB
23
Die Methode von @StockB vcsjones ist nicht gepuffert ... = sehr speicherintensiv für große Dateien. Ich schlage vor, Sie arbeiten mit Streams: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))Dies gibt Ihnen eine geringe Speichernutzung und keine Beschränkung auf 2 GB .
Davor Josipovic
20
@davor, das den Stream für einen unbestimmten Zeitraum offen hält, sodass Sie die Datei erst löschen können, wenn Powershell geschlossen ist. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)dann $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))dann$stream.Close()
Joe Amenta
57

Wenn Sie die PowerShell-Community-Erweiterungen verwenden, gibt es ein Get-Hash-Commandlet, das dies auf einfache Weise erledigt:

C:\PS> "hello world" | Get-Hash -Algorithm MD5


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764
Keith Hill
quelle
10
Get-Hash stammt von PowerShell Community Extensions. Wenn Sie das Paket nicht verwenden können oder wollen, haben sie ein Cmdlet Get-FileHashin Vanilla PowerShell 4.0 hinzugefügt . Vide TechNet .
Tomasz Cudziło
Beachten Sie, dass diese (und wahrscheinlich die meisten PS-Lösungen) die Zeichenfolge als UTF-16 (Little-Endian?) Codiert.
Christian Mann
Der Link zu PowerShell Community Extensions leitet zum CodePlex-Archiv weiter (CodePlex wurde 2017 geschlossen). Vielleicht zum GitHub wechseln ? (Ist der neue Master-Standort auf GitHub?)
Peter Mortensen
16

Hier sind die beiden Zeilen, ändern Sie einfach "Hallo" in Zeile 2:

PS C:\> [Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\> [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("hello", "MD5")
AvkashChauhan
quelle
1
Das Ergebnis entspricht nicht der Ausgabe, die ich mit der akzeptierten Antwort erhalte. Es berechnet den Hash des STRING "Hallo", nicht einer DATEI, die durch einen Pfad definiert wird, durch den ich "Hallo" ersetze, richtig?
RobertG
1
Stimmt, aber OP hat nicht nach einer Datei gefragt, und ich bin hierher gekommen, um nach einer String-Lösung zu suchen
Chris F. Carroll,
16

Hier ist eine Funktion, die relative und absolute Pfade verarbeitet:

function md5hash($path)
{
    $fullPath = Resolve-Path $path
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $file = [System.IO.File]::Open($fullPath,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
    try {
        [System.BitConverter]::ToString($md5.ComputeHash($file))
    } finally {
        $file.Dispose()
    }
}

Vielen Dank an @davor oben für den Vorschlag, Open () anstelle von ReadAllBytes () zu verwenden, und an @ jpmc26 für den Vorschlag, einen finally-Block zu verwenden.

David
quelle
2
Dieser Ansatz ist meiner Meinung nach besser als der von vcsjones und Keith, da Dateien von mehr als 2 GB eingegeben werden können und keine Erweiterungen oder PowerShell 4.0 erforderlich sind.
Chirag Bhatia - chirag64
1
Der DisposeAnruf sollte in einem finallyBlock sein.
jpmc26
12

Ein weiterer integrierter Befehl, der seit 2003 standardmäßig in Windows installiert ist , ist Certutil , das natürlich auch von PowerShell aus aufgerufen werden kann.

CertUtil -hashfile file.foo MD5

(Vorsichtsmaßnahme: MD5 sollte für maximale Robustheit in allen Kappen enthalten sein.)

Danekan
quelle
Dies ist eine gute Option, wenn sie FipsAlgorithmPolicyaktiviert ist.
William John Holden
9

Es gibt viele Beispiele online mit ComputeHash (). Meine Tests haben gezeigt, dass dies beim Ausführen über eine Netzwerkverbindung sehr langsam war. Das folgende Snippet läuft für mich viel schneller, Ihr Kilometerstand kann jedoch variieren:

$md5 = [System.Security.Cryptography.MD5]::Create("MD5")
$fd = [System.IO.File]::OpenRead($file)
$buf = New-Object byte[] (1024*1024*8) # 8 MB buffer
while (($read_len = $fd.Read($buf,0,$buf.length)) -eq $buf.length){
    $total += $buf.length
    $md5.TransformBlock($buf,$offset,$buf.length,$buf,$offset)
    Write-Progress -Activity "Hashing File" `
       -Status $file -percentComplete ($total/$fd.length * 100)
}

# Finalize the last read
$md5.TransformFinalBlock($buf, 0, $read_len)
$hash = $md5.Hash

# Convert hash bytes to a hexadecimal formatted string
$hash | foreach { $hash_txt += $_.ToString("x2") }
Write-Host $hash_txt
cmcginty
quelle
1
Ihre Methode überwindet das 2-GB-Limit von ReadAllBytes aus anderen Antworten, genau das, was ich brauchte.
Jay
Was macht der Backtick in der write-progressLeitung? Der Syntax-Textmarker scheint es nicht zu mögen.
mwfearnley
1
@mwfearnley Der Backtick ermöglicht die Fortsetzung der Leitung. blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
cmcginty
6

Diese Site enthält ein Beispiel: Verwenden von Powershell für MD5-Prüfsummen . Es verwendet das .NET-Framework, um eine Instanz des MD5-Hash-Algorithmus zu instanziieren und den Hash zu berechnen.

Hier ist der Code aus dem Artikel, der Stephens Kommentar enthält:

param
(
  $file
)

$algo = [System.Security.Cryptography.HashAlgorithm]::Create("MD5")
$stream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open,
    [System.IO.FileAccess]::Read)

$md5StringBuilder = New-Object System.Text.StringBuilder
$algo.ComputeHash($stream) | % { [void] $md5StringBuilder.Append($_.ToString("x2")) }
$md5StringBuilder.ToString()

$stream.Dispose()
Neontapir
quelle
1
Gut, außer dass es nicht für schreibgeschützte Dateien funktioniert! Es benötigt $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Read)
Stephen Connolly
1
Wenn der Link jemals stirbt, ist die Antwort völlig nutzlos. stackoverflow.com/help/how-to-answer
Ich bin mit Monica
1
Als Antwort auf Ihre Vermutung habe ich den Code aus dem Artikel hier ausgeschnitten und eingefügt. Ich habe das letztes Jahr nicht gemacht, weil ich dachte, es sei Plagiat. Durch das Hinzufügen von Stephens schreibgeschützter Anpassung hatte ich das Gefühl, dass es sich lohnt, etwas zu posten.
Neontapir
@neontapir nur um zu sagen: etwas wörtlich (oder mit Anpassungen) zu posten ist nur dann ein Plagiat, wenn Sie die Quelle nicht anerkennen. Das Urheberrecht (rechtlich oder moralisch) ist ein separates Thema, aber ich würde mich bei den meisten Codefragmenten nicht darum kümmern.
mwfearnley
6

Wie in der akzeptierten Antwort angegeben, Get-FileHashist die Verwendung mit Dateien einfach, es ist jedoch auch möglich, sie mit Zeichenfolgen zu verwenden:

$s = "asdf"
Get-FileHash -InputStream ([System.IO.MemoryStream]::New([System.Text.Encoding]::ASCII.GetBytes($s)))
wensveen
quelle
5

Es gibt jetzt eine Get-FileHash-Funktion, die sehr praktisch ist.

PS C:\> Get-FileHash C:\Users\Andris\Downloads\Contoso8_1_ENT.iso -Algorithm SHA384 | Format-List

Algorithm : SHA384
Hash      : 20AB1C2EE19FC96A7C66E33917D191A24E3CE9DAC99DB7C786ACCE31E559144FEAFC695C58E508E2EBBC9D3C96F21FA3
Path      : C:\Users\Andris\Downloads\Contoso8_1_ENT.iso

Wechseln Sie einfach SHA384zu MD5.

Das Beispiel stammt aus der offiziellen Dokumentation von PowerShell 5.1 . Die Dokumentation enthält weitere Beispiele.

Braulio J. Solano
quelle
1

Dadurch wird ein MD5-Hash für eine Datei auf einem Remotecomputer zurückgegeben:

Invoke-Command -ComputerName RemoteComputerName -ScriptBlock {
    $fullPath = Resolve-Path 'c:\Program Files\Internet Explorer\iexplore.exe'
    $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
    $file = [System.IO.File]::OpenRead($fullPath)
    $hash = [System.BitConverter]::ToString($md5.ComputeHash($file))
    $hash -replace "-", ""
    $file.Dispose()
}
YetiSized
quelle
1

Beispiel für eine Rechtsklick-Menüoption:

[HKEY_CLASSES_ROOT\*\shell\SHA1 PS check\command]
@="C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -NoExit -Command Get-FileHash -Algorithm SHA1 '%1'"
Niklas E.
quelle
1

PowerShell One-Liner (String zu Hash)

MD5

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA1

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA1CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA256

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA384

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA384CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")

SHA512

([System.BitConverter]::ToString((New-Object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider).ComputeHash((New-Object -TypeName System.Text.UTF8Encoding).GetBytes("Hello, World!")))).Replace("-","")
YourWishIsMine
quelle
0

Hier ist ein hübsches Druckbeispiel, das versucht, den SHA256-Fingerabdruck zu überprüfen. Ich habe gpg4win v3.0.3 mit PowerShell v4 heruntergeladen (erforderlich Get-FileHash).

Laden Sie das Paket von https://www.gpg4win.org/download.html herunter , öffnen Sie PowerShell, holen Sie sich den Hash von der Download-Seite und führen Sie Folgendes aus:

cd ${env:USERPROFILE}\Downloads
$file = "gpg4win-3.0.3.exe"

# Set $hash to the hash reference from the download page:
$hash = "477f56212ee60cc74e0c5e5cc526cec52a069abff485c89c2d57d1b4b6a54971"

# If you have an MD5 hash: # $hashAlgo="MD5"
$hashAlgo = "SHA256"

$computed_hash = (Get-FileHash -Algorithm $hashAlgo $file).Hash.ToUpper()
if ($computed_hash.CompareTo($hash.ToUpper()) -eq 0 ) {
    Write-Output "Hash matches for file $file" 
} 
else { 
    Write-Output ("Hash DOES NOT match for file {0}: `nOriginal hash: {1} `nComputed hash: {2}" -f ($file, $hash.ToUpper(), $computed_hash)) 
}

Ausgabe:

Hash matches for file gpg4win-3.0.3.exe
Thomas
quelle
0

Hier ist ein einzeiliges Befehlsbeispiel, bei dem sowohl die richtige Prüfsumme der Datei , wie Sie sie gerade heruntergeladen haben, berechnet als auch mit der veröffentlichten Prüfsumme des Originals verglichen wird.

Zum Beispiel habe ich ein Beispiel für Downloads aus dem Apache JMeter-Projekt geschrieben . In diesem Fall haben Sie:

  1. heruntergeladene Binärdatei
  2. Prüfsumme des Originals, das in file.md5 als eine Zeichenfolge im Format veröffentlicht wird:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Mit diesem PowerShell-Befehl können Sie dann die Integrität der heruntergeladenen Datei überprüfen:

PS C:\Distr> (Get-FileHash .\apache-jmeter-4.0.zip -Algorithm MD5).Hash -eq (Get-Content .\apache-jmeter-4.0.zip.md5 | Convert-String -Example "hash path=hash")

Ausgabe:

True

Erläuterung:

Der erste Operand des -eqOperators ergibt sich aus der Berechnung der Prüfsumme für die Datei:

(Get-FileHash .\apache-jmeter-4.0.zip -Algorithm MD5).Hash

Der zweite Operand ist der veröffentlichte Prüfsummenwert. Wir erhalten zuerst den Inhalt der Datei.md5, bei der es sich um eine Zeichenfolge handelt, und extrahieren dann den Hashwert basierend auf dem Zeichenfolgenformat:

Get-Content .\apache-jmeter-4.0.zip.md5 | Convert-String -Example "hash path=hash"

Sowohl file als auch file.md5 müssen sich für diese Befehlsarbeit im selben Ordner befinden.

Egor B Eremeev
quelle
0

Folgendes verwende ich, um einen konsistenten Hashwert zu erhalten:

function New-CrcTable {
    [uint32]$c = $null
    $crcTable = New-Object 'System.Uint32[]' 256

    for ($n = 0; $n -lt 256; $n++) {
        $c = [uint32]$n
        for ($k = 0; $k -lt 8; $k++) {
            if ($c -band 1) {
                $c = (0xEDB88320 -bxor ($c -shr 1))
            }
            else {
                $c = ($c -shr 1)
            }
        }
        $crcTable[$n] = $c
    }

    Write-Output $crcTable
}

function Update-Crc ([uint32]$crc, [byte[]]$buffer, [int]$length, $crcTable) {
    [uint32]$c = $crc

    for ($n = 0; $n -lt $length; $n++) {
        $c = ($crcTable[($c -bxor $buffer[$n]) -band 0xFF]) -bxor ($c -shr 8)
    }

    Write-Output $c
}

function Get-CRC32 {
    <#
        .SYNOPSIS
            Calculate CRC.
        .DESCRIPTION
            This function calculates the CRC of the input data using the CRC32 algorithm.
        .EXAMPLE
            Get-CRC32 $data
        .EXAMPLE
            $data | Get-CRC32
        .NOTES
            C to PowerShell conversion based on code in https://www.w3.org/TR/PNG/#D-CRCAppendix

            Author: Øyvind Kallstad
            Date: 06.02.2017
            Version: 1.0
        .INPUTS
            byte[]
        .OUTPUTS
            uint32
        .LINK
            https://communary.net/
        .LINK
            https://www.w3.org/TR/PNG/#D-CRCAppendix

    #>
    [CmdletBinding()]
    param (
        # Array of Bytes to use for CRC calculation
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [byte[]]$InputObject
    )

    $dataArray = @()
    $crcTable = New-CrcTable
    foreach ($item  in $InputObject) {
        $dataArray += $item
    }
    $inputLength = $dataArray.Length
    Write-Output ((Update-Crc -crc 0xffffffffL -buffer $dataArray -length $inputLength -crcTable $crcTable) -bxor 0xffffffffL)
}

function GetHash() {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$InputString
    )

    $bytes = [System.Text.Encoding]::UTF8.GetBytes($InputString)
    $hasCode = Get-CRC32 $bytes
    $hex = "{0:x}" -f $hasCode
    return $hex
}

function Get-FolderHash {
    [CmdletBinding()]
    param(
        [Parameter(Position = 0, ValueFromPipeline = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$FolderPath
    )

    $FolderContent = New-Object System.Collections.ArrayList
    Get-ChildItem $FolderPath -Recurse | Where-Object {
        if ([System.IO.File]::Exists($_)) {
            $FolderContent.AddRange([System.IO.File]::ReadAllBytes($_)) | Out-Null
        }
    }

    $hasCode = Get-CRC32 $FolderContent
    $hex = "{0:x}" -f $hasCode
    return $hex.Substring(0, 8).ToLower()
}
user2529654
quelle
Woher haben Sie den PowerShell-Code kopiert? https://communary.net/ ?
Peter Mortensen
0

Hier ist das Snippet, mit dem ich das MD5 für eine bestimmte Zeichenfolge erhalte:

$text = "text goes here..."
$md5  = [Security.Cryptography.MD5CryptoServiceProvider]::new()
$utf8 = [Text.UTF8Encoding]::UTF8
$bytes= $md5.ComputeHash($utf8.GetBytes($text))
$hash = [string]::Concat($bytes.foreach{$_.ToString("x2")}) 
Peter
quelle