Cómo obtener una suma de comprobación MD5 en PowerShell


179

Me gustaría calcular una suma de verificación MD5 de algún contenido. ¿Cómo hago esto en PowerShell?


3
¿Qué es "algún contenido"? ¿un archivo? ¿cuerda?
vcsjones

Respuestas:


326

Si el contenido es una cadena:

$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 el contenido es un archivo:

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

A partir de PowerShell versión 4, esto es fácil de hacer para los archivos Get-FileHashlistos para usar con el cmdlet:

Get-FileHash <filepath> -Algorithm MD5

Esto es ciertamente preferible ya que evita los problemas que ofrece la primera solución identificada en los comentarios (usa una secuencia, la cierra y admite archivos grandes).


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."Como un chico de Linux nuevo en Powershell, estoy muy molesto con las dificultades que estoy teniendo para obtener una suma md5, que sería simplemente md5sum file.exten Linux.
StockB

La respuesta de @StockB Keith a continuación probablemente lo manejará mejor. Estoy de acuerdo, hay algunas deficiencias con powershell.
vcsjones

55
Tengo instalado PowerShell de vainilla sin extensiones, por lo que me descompuse y descargué un clon md5sum de línea de comandos, que funciona muy bien. Quiero que me gusten las cosas de Microsoft, pero no puedo.
StockB

23
El método de @StockB vcsjones no está almacenado ... = memoria muy exigente para archivos grandes. Le sugiero que trabaje con transmisiones: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))esto le da un bajo uso de memoria y no hay límite de 2GB .
Davor Josipovic el

20
@davor que mantiene la transmisión abierta durante un período de tiempo indeterminado, por lo que no puede eliminar el archivo hasta que Powershell esté cerrado. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)entonces $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))luego$stream.Close()
Joe Amenta

57

Si está utilizando las Extensiones de comunidad de PowerShell, hay un comando Get-Hash que lo hará fácilmente:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764

10
Get-Hash proviene de PowerShell Community Extensions. Cuando no puede o no quiere usar el paquete, han agregado un cmdlet Get-FileHashen Vanilla PowerShell 4.0. Vide TechNet .
Tomasz Cudziło

Tenga en cuenta que esto (y probablemente la mayoría de las soluciones de PS) codifica la cadena como UTF-16 (little-endian?).
Christian Mann

El enlace a PowerShell Community Extensions redirige al archivo CodePlex (CodePlex cerró en 2017). ¿Quizás cambiar al de GitHub ? (¿Es la nueva ubicación maestra en GitHub?)
Peter Mortensen el

16

Aquí están las dos líneas, simplemente cambie "hola" en la línea # 2:

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

1
El resultado de esto no es igual a la salida que obtengo con la respuesta aceptada. Calcula el hash de STRING "hola", no de un ARCHIVO que estaría definido por cualquier ruta con la que reemplace "hola", ¿correcto?
RobertG

1
Es cierto, pero OP no pidió un archivo, y vine aquí buscando una solución de cadena
Chris F Carroll

16

Aquí hay una función que uso que maneja rutas relativas y absolutas:

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

Gracias a @davor arriba por la sugerencia de usar Open () en lugar de ReadAllBytes () y a @ jpmc26 por la sugerencia de usar un bloque finalmente.


2
Este enfoque es mejor en mi humilde opinión que vcsjones y Keith porque puede recibir archivos de más de 2 GB y no necesita extensiones ni PowerShell 4.0.
Chirag Bhatia - chirag64

1
La Disposellamada debe estar en un finallybloque.
jpmc26

12

Otro comando incorporado que se instaló por mucho tiempo en Windows de forma predeterminada desde 2003 es Certutil , que por supuesto también se puede invocar desde PowerShell.

CertUtil -hashfile file.foo MD5

(Advertencia: MD5 debe estar en mayúsculas para máxima robustez)


1
Esta es una buena opción cuando FipsAlgorithmPolicyestá habilitada.
William John Holden

9

Hay muchos ejemplos en línea usando ComputeHash (). Mi prueba mostró que esto era muy lento cuando se ejecutaba a través de una conexión de red. El fragmento a continuación funciona mucho más rápido para mí, sin embargo, su kilometraje puede variar:

$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
Su método supera el límite de 2 Gb de ReadAllBytes de otras respuestas, que es exactamente lo que necesitaba.
Jay

¿Qué hace el backtick en la write-progresslínea? Al resaltador de sintaxis no parece gustarle.
mwfearnley

1
@mwfearnley El backtick permite la continuación de la línea. blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
cmcginty

6

Este sitio tiene un ejemplo: Uso de Powershell para sumas de verificación MD5 . Utiliza el marco .NET para crear una instancia del algoritmo hash MD5 para calcular el hash.

Aquí está el código del artículo, incorporando el comentario 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()

1
Bueno, excepto que no funciona para archivos de solo lectura. Necesita $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Leer)
Stephen Connolly

1
Si el enlace alguna vez muere, la respuesta será bastante inútil. stackoverflow.com/help/how-to-answer
Estoy con Monica el

1
En respuesta a lo que presumo que fue su voto negativo, corté y pegué el código del artículo aquí. No hice eso el año pasado, porque sentí que era plagio. Agregar la adaptación de solo lectura de Stephen me hizo sentir que valía la pena publicarlo.
neontapir

@neontapir solo para decir: publicar algo al pie de la letra (o con adaptaciones) es solo plagio si no reconoce la fuente. Los derechos de autor (legal o moralmente) son un tema separado, pero no tendré que preocuparme por eso con la mayoría de los fragmentos de código.
mwfearnley

6

Como se indica en la respuesta aceptada, Get-FileHashes fácil de usar con archivos, pero también es posible usarlo con cadenas:

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

5

Ahora hay una función Get-FileHash que es muy útil.

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

Solo cambia SHA384a MD5.

El ejemplo es de la documentación oficial de PowerShell 5.1 . La documentación tiene más ejemplos.



3

PowerShell One-Liners (cadena 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

Esto devolverá un hash MD5 para un archivo en una computadora remota:

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

Muestra de la opción de menú del botón derecho también:

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

0

Aquí hay un bonito ejemplo de impresión que intenta verificar la huella digital SHA256. Descargué gpg4win v3.0.3 usando PowerShell v4 (requiere Get-FileHash).

Descargue el paquete de https://www.gpg4win.org/download.html , abra PowerShell, tome el hash de la página de descarga y ejecute:

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

Salida:

Hash matches for file gpg4win-3.0.3.exe

0

Aquí hay un ejemplo de comando de una línea con ambos computando la suma de verificación adecuada del archivo , como la que acaba de descargar, y la comparación con la suma de verificación publicada del original.

Por ejemplo, escribí un ejemplo para descargas del proyecto Apache JMeter . En este caso tienes:

  1. archivo binario descargado
  2. suma de comprobación del original que se publica en file.md5 como una cadena en el formato:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Luego, utilizando este comando de PowerShell, puede verificar la integridad del archivo descargado:

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

Salida:

True

Explicación:

El primer operando del -eqoperador es el resultado de calcular la suma de comprobación para el archivo:

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

El segundo operando es el valor de suma de control publicado. Primero obtenemos contenido del archivo.md5, que es una cadena y luego extraemos el valor hash en función del formato de cadena:

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

Tanto file como file.md5 deben estar en la misma carpeta para que este comando funcione.


0

Esto es lo que uso para obtener un valor hash consistente:

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

¿De dónde has copiado el código de PowerShell? https://communary.net/ ?
Peter Mortensen el

0

Aquí está el fragmento que estoy usando para obtener el MD5 para una cadena dada:

$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")}) 
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.