Comment obtenir une somme de contrôle MD5 dans PowerShell

179

Je voudrais calculer une somme de contrôle MD5 de certains contenus. Comment faire cela dans PowerShell?

Luc101
la source
3
Qu'est-ce qu'un "certain contenu"? un fichier? chaîne?
vcsjones

Réponses:

326

Si le contenu est une chaîne:

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

Si le contenu est un fichier:

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

À partir de PowerShell version 4, cela est facile à faire pour les fichiers prêts à l' Get-FileHashemploi avec l' applet de commande:

Get-FileHash <filepath> -Algorithm MD5

C'est certainement préférable car cela évite les problèmes qu'offre la première solution tels qu'identifiés dans les commentaires (utilise un flux, le ferme et prend en charge les gros fichiers).

vcsjones
la source
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."En tant que nouveau venu de Linux sur Powershell, je suis très ennuyé par les difficultés que j'ai pour obtenir une somme md5, qui serait simplement md5sum file.extsous Linux.
StockB
La réponse de @StockB Keith ci-dessous va probablement mieux gérer cela. Je suis d'accord, il y a quelques lacunes avec PowerShell.
vcsjones
5
J'ai installé vanilla PowerShell sans extensions, alors je suis tombé en panne et j'ai téléchargé un clone md5sum en ligne de commande à la place, qui fonctionne très bien. Je veux aimer les trucs de Microsoft, mais je ne peux pas.
StockB
23
La méthode de @StockB vcsjones n'est pas mise en mémoire tampon ... = mémoire très gourmande pour les gros fichiers. Je vous suggère de travailler avec des flux: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))cela vous donne une faible utilisation de la mémoire et aucune limite de 2 Go .
Davor Josipovic
20
@davor qui maintient le flux ouvert pendant une période indéterminée, vous ne pouvez donc pas supprimer le fichier tant que Powershell n'est pas fermé. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)puis $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))puis$stream.Close()
Joe Amenta
57

Si vous utilisez les extensions de communauté PowerShell, il existe une commande Get-Hash qui le fera facilement:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764
Keith Hill
la source
10
Get-Hash provient des extensions de communauté PowerShell. Lorsque vous ne pouvez pas ou ne voulez pas utiliser le package, ils ont ajouté une applet de commande Get-FileHashdans vanilla PowerShell 4.0. Vide TechNet .
Tomasz Cudziło
Notez que ceci (et probablement la plupart des solutions PS) code la chaîne en UTF-16 (petit-boutiste?).
Christian Mann
Le lien vers les extensions de communauté PowerShell redirige vers l'archive CodePlex (CodePlex fermé en 2017). Peut-être changer pour le GitHub ? (Le nouvel emplacement principal est-il sur GitHub?)
Peter Mortensen
16

Voici les deux lignes, changez simplement "bonjour" à la ligne 2:

PS C:\> [Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\> [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("hello", "MD5")
AvkashChauhan
la source
1
Le résultat ne correspond pas à la sortie que j'obtiens avec la réponse acceptée. Il calcule le hachage de la STRING "hello", pas d'un FILE qui serait défini par n'importe quel chemin que je remplace par "hello", n'est-ce pas?
RobertG
1
C'est vrai, mais OP n'a pas demandé de fichier, et je suis venu ici à la recherche d'une solution de chaîne
Chris F Carroll
16

Voici une fonction que j'utilise qui gère les chemins relatifs et absolus:

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

Merci à @davor ci-dessus pour la suggestion d'utiliser Open () au lieu de ReadAllBytes () et à @ jpmc26 pour la suggestion d'utiliser un bloc finally.

David
la source
2
Cette approche est meilleure à mon humble avis que celle de vcsjones et de Keith car elle peut prendre en charge des fichiers de plus de 2 Go et elle n'a pas besoin d'extensions ou de PowerShell 4.0.
Chirag Bhatia - chirag64
1
L' Disposeappel doit être dans un finallybloc.
jpmc26
12

Une autre commande intégrée qui est installée depuis longtemps dans Windows par défaut et qui remonte à 2003 est Certutil , qui peut bien sûr être également appelée à partir de PowerShell.

CertUtil -hashfile file.foo MD5

(Attention: MD5 doit être en majuscules pour une robustesse maximale)

danekan
la source
1
C'est une bonne option quand FipsAlgorithmPolicyest activé.
William John Holden le
9

Il existe de nombreux exemples en ligne utilisant ComputeHash (). Mes tests ont montré que c'était très lent lors de l'exécution sur une connexion réseau. L'extrait ci-dessous est beaucoup plus rapide pour moi, mais votre kilométrage peut varier:

$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
la source
1
Votre méthode dépasse la limite de 2 Go de ReadAllBytes à partir d'autres réponses, ce qui est exactement ce dont j'avais besoin.
Jay
Que fait le backtick sur la write-progressligne? Le surligneur de syntaxe ne semble pas l'apprécier.
mwfearnley
1
@mwfearnley Le backtick permet la continuation de la ligne. blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
cmcginty
6

Ce site a un exemple: Utilisation de Powershell pour les sommes de contrôle MD5 . Il utilise le framework .NET pour instancier une instance de l'algorithme de hachage MD5 afin de calculer le hachage.

Voici le code de l'article, intégrant le commentaire de 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()
néontapir
la source
1
Bien sauf que cela ne fonctionne pas pour les fichiers en lecture seule! Il a besoin de $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Read)
Stephen Connolly
1
Si le lien meurt un jour, la réponse sera tout à fait inutile. stackoverflow.com/help/how-to-answer
Je suis avec Monica
1
En réponse à ce que je présume être votre vote défavorable, j'ai coupé et collé le code de l'article ici. Je ne l'ai pas fait l'année dernière, car je sentais que c'était du plagiat. L'ajout de l'adaptation en lecture seule de Stephen m'a fait sentir que cela valait la peine d'être publié.
neontapir
@neontapir juste pour dire: publier quelque chose textuellement (ou avec des adaptations) n'est du plagiat que si vous ne reconnaissez pas la source. Le droit d'auteur (légalement ou moralement) est un problème distinct, mais je n'aurais pas tendance à m'inquiéter à ce sujet avec la plupart des extraits de code.
mwfearnley le
6

Comme indiqué dans la réponse acceptée, Get-FileHashest facile à utiliser avec des fichiers, mais il est également possible de l'utiliser avec des chaînes:

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

Il existe maintenant une fonction Get-FileHash qui est très pratique.

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

Changez simplement SHA384pour MD5.

L'exemple provient de la documentation officielle de PowerShell 5.1 . La documentation a plus d'exemples.

Braulio J. Solano
la source
3

Cela devient une ligne unique si vous téléchargez le vérificateur d'intégrité de la somme de contrôle des fichiers (FCIV) de Microsoft.

J'ai téléchargé FCIV à partir d'ici: Disponibilité et description de l'utilitaire File Checksum Integrity Verifier

Exécutez la commande suivante. J'avais dix fichiers à vérifier.

Get-ChildItem WTAM*.tar | % {.\fciv $_.Name}
RonDBA
la source
3

PowerShell One-Liners (chaîne en hachage)

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("-","")
Votre souhait est à moi
la source
1

Cela renverra un hachage MD5 pour un fichier sur un ordinateur distant:

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
la source
1

Exemple d'option de menu contextuel également:

[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
la source
0

Voici un joli exemple d'impression tentant de vérifier l'empreinte digitale SHA256. J'ai téléchargé gpg4win v3.0.3 en utilisant PowerShell v4 (nécessite Get-FileHash).

Téléchargez le package à partir de https://www.gpg4win.org/download.html , ouvrez PowerShell, récupérez le hachage sur la page de téléchargement et exécutez:

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

Production:

Hash matches for file gpg4win-3.0.3.exe
Thomas
la source
0

Voici un exemple de commande en une ligne avec à la fois le calcul de la somme de contrôle appropriée du fichier , comme vous venez de le télécharger, et la comparaison avec la somme de contrôle publiée de l'original.

Par exemple, j'ai écrit un exemple de téléchargement à partir du projet Apache JMeter . Dans ce cas, vous avez:

  1. fichier binaire téléchargé
  2. somme de contrôle de l'original qui est publié dans le fichier.md5 sous la forme d'une chaîne au format:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Ensuite, à l'aide de cette commande PowerShell, vous pouvez vérifier l'intégrité du fichier téléchargé:

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

Production:

True

Explication:

Le premier opérande d' -eqopérateur est le résultat du calcul de la somme de contrôle du fichier:

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

Le deuxième opérande est la valeur de la somme de contrôle publiée. Nous obtenons d'abord le contenu du fichier.md5 qui est une chaîne, puis nous extrayons la valeur de hachage en fonction du format de la chaîne:

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

Le fichier et le fichier.md5 doivent être dans le même dossier pour que cette commande fonctionne.

Egor B Eremeev
la source
0

C'est ce que j'utilise pour obtenir une valeur de hachage cohérente:

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
la source
D'où avez-vous copié le code PowerShell? https://communary.net/ ?
Peter Mortensen
0

Voici l'extrait que j'utilise pour obtenir le MD5 pour une chaîne donnée:

$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
la source