Come ottenere un checksum MD5 in PowerShell


Risposte:


326

Se il contenuto è una stringa:

$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)))

Se il contenuto è un file:

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

A partire da PowerShell versione 4, questo è facile da fare per i file Get-FileHashpronti all'uso con il cmdlet:

Get-FileHash <filepath> -Algorithm MD5

Questo è certamente preferibile poiché evita i problemi che la prima soluzione offre come identificati nei commenti (usa un flusso, lo chiude e supporta file di grandi dimensioni).


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."Come un ragazzo Linux nuovo a Powershell, sono molto infastidito dalle difficoltà che sto avendo per ottenere una somma md5, che sarebbe semplicemente md5sum file.extsu Linux.
StockB

@StockB La risposta di Keith qui sotto probabilmente lo gestirà meglio. Sono d'accordo, ci sono alcune carenze con PowerShell.
vcsjones,

5
Ho installato PowerShell vanilla senza estensioni, quindi ho interrotto e scaricato un clone md5sum da riga di comando, che funziona alla grande. Voglio apprezzare le cose di Microsoft, ma proprio non posso.
StockB,

23
@StockB Il metodo di vcsjones non è bufferizzato ... = memoria molto impegnativa per file di grandi dimensioni. Ti suggerisco di lavorare con i flussi: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))questo ti dà un basso utilizzo della memoria e nessun limite di 2 GB .
Davor Josipovic

20
@davor che mantiene aperto lo stream per un periodo di tempo indeterminato, quindi non è possibile eliminare il file fino alla chiusura di Powershell. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)poi $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))poi$stream.Close()
Joe Amenta,

57

Se si utilizzano le estensioni della community di PowerShell, è disponibile un commandlet Get-Hash che lo farà facilmente:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764

10
Get-Hash proviene dalle estensioni della community di PowerShell. Quando non è possibile o non si desidera utilizzare il pacchetto, è stato aggiunto un cmdlet Get-FileHashin PowerShell 4.0 vaniglia. Vide TechNet .
Tomasz Cudziło,

Nota che questa (e probabilmente la maggior parte delle soluzioni PS) codifica la stringa come UTF-16 (little-endian?).
Christian Mann,

Il collegamento a PowerShell Community Extensions reindirizza all'archivio CodePlex (CodePlex chiuso nel 2017). Forse passare a quello GitHub ? (La nuova posizione principale su GitHub?)
Peter Mortensen,

16

Ecco le due righe, basta cambiare "ciao" nella riga # 2:

PS C:\> [Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\> [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("hello", "MD5")

1
Il risultato di questo non equivale all'output che ottengo con la risposta accettata. Calcola l'hash dello STRING "ciao", non di un FILE che sarebbe definito da qualsiasi percorso con cui sostituisco "ciao", giusto?
RobertG,

1
È vero, ma OP non ha richiesto un file e sono venuto qui alla ricerca di una soluzione di stringa
Chris F Carroll,

16

Ecco una funzione che uso che gestisce percorsi relativi e assoluti:

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()
    }
}

Grazie a @davor sopra per il suggerimento di usare Open () invece di ReadAllBytes () e @ jpmc26 per il suggerimento di usare un blocco finally.


2
Questo approccio è IMHO migliore di vcsjones e di Keith perché può accettare input di file di dimensioni superiori a 2 GB e non ha bisogno di estensioni o PowerShell 4.0.
Chirag Bhatia - chirag64,

1
La Disposechiamata dovrebbe essere in un finallyblocco.
jpmc26,

12

Un altro comando integrato installato da tempo in Windows per impostazione predefinita risalente al 2003 è Certutil , che ovviamente può essere invocato anche da PowerShell.

CertUtil -hashfile file.foo MD5

(Avvertenza: MD5 dovrebbe essere in tutti i tappi per la massima robustezza)


1
Questa è una buona opzione quando FipsAlgorithmPolicyè abilitata.
William John Holden,

9

Ci sono molti esempi online usando ComputeHash (). I miei test hanno dimostrato che ciò è stato molto lento durante l'esecuzione su una connessione di rete. Lo snippet di seguito è molto più veloce per me, tuttavia il tuo chilometraggio può variare:

$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

1
Il metodo supera il limite di 2 GB di ReadAllBytes da altre risposte, che è esattamente quello di cui avevo bisogno.
Jay,

Cosa fa il backtick sulla write-progresslinea? L'evidenziatore della sintassi non sembra gradirlo.
mwfearnley,

1
@mwfearnley Il backtick abilita la continuazione della linea. blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
cmcginty

6

Questo sito ha un esempio: utilizzo di Powershell per checksum MD5 . Utilizza il framework .NET per istanziare un'istanza dell'algoritmo hash MD5 per calcolare l'hash.

Ecco il codice dell'articolo, che incorpora il commento di Stephen:

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()

1
Buono tranne che non funziona per i file di sola lettura! Ha bisogno di $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Read)
Stephen Connolly,

1
Se il collegamento dovesse mai morire, la risposta sarà del tutto inutile. stackoverflow.com/help/how-to-answer
Sono con Monica il

1
In risposta a quello che presumo fosse il tuo downvote, ho tagliato e incollato il codice dall'articolo qui. Non l'ho fatto l'anno scorso, perché sentivo che era un plagio. L'aggiunta dell'adattamento di sola lettura di Stephen mi ha fatto sentire che valeva la pena pubblicare.
neontapir,

@neontapir solo per dire: pubblicare qualcosa di verbale (o con adattamenti) è solo un plagio se non riconosci la fonte. Il copyright (legalmente o moralmente) è un problema separato, ma non tenderei a preoccuparmene con la maggior parte dei frammenti di codice.
mwfearnley,

6

Come indicato nella risposta accettata, Get-FileHashè facile da usare con i file, ma è anche possibile usarlo con le stringhe:

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

5

Ora c'è una funzione Get-FileHash che è molto utile.

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

Passa SHA384a MD5.

L'esempio è tratto dalla documentazione ufficiale di PowerShell 5.1 . La documentazione ha più esempi.



3

PowerShell One-Liners (da stringa a 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("-","")

1

Ciò restituirà un hash MD5 per un file su un computer remoto:

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()
}

1

Esempio per l'opzione di menu del tasto destro:

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

0

Ecco un esempio di stampa piuttosto che tenta di verificare l'impronta digitale SHA256. Ho scaricato gpg4win v3.0.3 usando PowerShell v4 (richiede Get-FileHash).

Scarica il pacchetto da https://www.gpg4win.org/download.html , apri PowerShell, prendi l'hash dalla pagina di download ed esegui:

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)) 
}

Produzione:

Hash matches for file gpg4win-3.0.3.exe

0

Ecco un esempio di comando a una riga con entrambi che calcolano il checksum corretto del file , come appena scaricato, sia il confronto con il checksum pubblicato dell'originale.

Ad esempio, ho scritto un esempio per i download dal progetto Apache JMeter . In questo caso hai:

  1. file binario scaricato
  2. checksum dell'originale pubblicato in file.md5 come una stringa nel formato:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Quindi, utilizzando questo comando PowerShell, è possibile verificare l'integrità del file scaricato:

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")

Produzione:

True

Spiegazione:

Il primo operando di -eqoperatore è il risultato del calcolo del checksum per il file:

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

Il secondo operando è il valore di checksum pubblicato. Innanzitutto otteniamo il contenuto del file.md5 che è una stringa e quindi estraiamo il valore hash in base al formato stringa:

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

Sia file che file.md5 devono trovarsi nella stessa cartella per questo comando.


0

Questo è quello che uso per ottenere un valore hash coerente:

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()
}

Da dove hai copiato il codice PowerShell? https://communary.net/ ?
Peter Mortensen,

0

Ecco lo snippet che sto usando per ottenere MD5 per una determinata stringa:

$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")}) 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.