Como obter uma soma de verificação MD5 no PowerShell


179

Gostaria de calcular uma soma de verificação MD5 de algum conteúdo. Como faço isso no PowerShell?


3
O que é "algum conteúdo"? um arquivo? corda?
— Vcsjones

Respostas:


326

Se o conteúdo for uma sequência:

$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 o conteúdo for um arquivo:

$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 do PowerShell versão 4, é fácil fazer isso com arquivos prontos para uso com o Get-FileHashcmdlet:

Get-FileHash <filepath> -Algorithm MD5

Isso certamente é preferível, pois evita os problemas que a primeira solução oferece, conforme identificado nos comentários (usa um fluxo, fecha e suporta arquivos 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 um cara do Linux novato no Powershell, estou muito irritado com as lutas que estou tendo em obter uma soma md5, que seria simplesmente md5sum file.extno Linux.
— StockB

A resposta do @StockB Keith abaixo provavelmente vai lidar com isso melhor. Eu concordo, há algumas falhas no PowerShell.
— Vcsjones

5
Eu tenho o PowerShell de baunilha instalado sem extensões, então eu quebrei e baixei um clone da linha de comando md5sum, o que funciona muito bem. Quero gostar das coisas da Microsoft, mas simplesmente não posso.
— StockB

23
O método do @StockB vcsjones não é armazenado em buffer ... = muita memória exigindo arquivos grandes. Eu sugiro que você trabalhe com fluxos: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))isso oferece baixo uso de memória e nenhum limite de 2 GB .
— Davor Josipovic

20
@davor que mantém o fluxo aberto por um período indeterminado, para que você não possa excluir o arquivo até que o Powershell seja fechado. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)em seguida, $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))em seguida,$stream.Close()
— Joe Amenta

57

Se você estiver usando as Extensões da comunidade do PowerShell, há um comando Get-Hash que fará isso facilmente:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764

10
O Get-Hash vem das Extensões da comunidade do PowerShell. Quando você não pode ou não usa o pacote, eles adicionaram um cmdlet Get-FileHashno vanilla PowerShell 4.0. Vide TechNet .
— Tomasz Cudziło

Observe que isso (e provavelmente a maioria das soluções PS) codifica a string como UTF-16 (little-endian?).
— Christian Mann

O link para as Extensões da comunidade do PowerShell é redirecionado para o arquivo CodePlex (o CodePlex foi fechado em 2017). Talvez mude para o GitHub ? (É a nova localização mestre no GitHub?)
— Peter Mortensen

16

Aqui estão as duas linhas, basta alterar "olá" na linha 2:

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

1
O resultado disso não é igual ao resultado que recebo com a resposta aceita. Ele calcula o hash do STRING "olá", não de um ARQUIVO que seria definido por qualquer caminho que eu substitua "olá", correto?
— RobertG

1
É verdade, mas OP não pediu um arquivo, e eu vim aqui à procura de solução de corda
— Chris F Carroll

16

Aqui está uma função que eu uso que lida com caminhos relativos e absolutos:

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

Agradecemos a @davor acima pela sugestão de usar Open () em vez de ReadAllBytes () e a @ jpmc26 pela sugestão de usar um bloco finalmente.


2
Essa abordagem é melhor IMHO que a de vcsjones e Keith, porque pode receber arquivos com mais de 2 GB e não precisa de extensões ou do PowerShell 4.0.
— precisa saber é o seguinte

1
A Disposechamada deve estar em um finallybloco.
— Jpmc26 4/04

12

Outro comando interno que há muito tempo é instalado no Windows por padrão desde 2003 é o Certutil , que também pode ser chamado pelo PowerShell.

CertUtil -hashfile file.foo MD5

(Advertência: MD5 deve estar em maiúsculas para máxima robustez)


1
Esta é uma boa opção quando FipsAlgorithmPolicyestá ativada.
— William John Holden

9

Existem muitos exemplos online usando o ComputeHash (). Meus testes mostraram que isso era muito lento ao executar uma conexão de rede. O trecho abaixo é muito mais rápido para mim, no entanto, sua milhagem pode 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
Seu método supera o limite de 2 GB de ReadAllBytes de outras respostas, que é exatamente o que eu precisava.
— Jay

O que o backtick na write-progresslinha faz? O marcador de sintaxe não parece gostar.
— Mkfearnley

1
@mwfearnley O backtick permite a continuação da linha. blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
— cmcginty

6

Este site tem um exemplo: Usando o PowerShell para MD5 Checksums . Ele usa a estrutura .NET para instanciar uma instância do algoritmo de hash MD5 para calcular o hash.

Aqui está o código do artigo, incorporando o comentário 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
Bom, exceto que não funciona para arquivos somente leitura! Ele precisa de US $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Read)
— Stephen Connolly

1
Se o link acabar, a resposta será completamente inútil. stackoverflow.com/help/how-to-answer
— Estou com Monica

1
Em resposta ao que presumo ter sido seu voto negativo, recortei e colei o código do artigo aqui. Não fiz isso no ano passado, porque senti que era plágio. Adicionar a adaptação somente leitura de Stephen me fez sentir que valia a pena postar.
— neontapir

@neontapir apenas para dizer: postar algo literalmente (ou com adaptações) é apenas plágio se você não reconhecer a fonte. Os direitos autorais (legal ou moralmente) são um problema separado, mas eu não tenderia a me preocupar com isso com a maioria dos trechos de código.
— mwfearnley 9/04

6

Conforme declarado na resposta aceita, Get-FileHashé fácil usar com arquivos, mas também é possível usá-lo com strings:

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

5

Agora existe uma função Get-FileHash que é muito ú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

Apenas mude SHA384para MD5.

O exemplo é da documentação oficial do PowerShell 5.1 . A documentação tem mais exemplos.



3

Linhas de alinhamento do PowerShell (seqüência de caracteres para 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

Isso retornará um hash MD5 para um arquivo em um computador 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

Exemplo de opção de menu com o botão direito do mouse também:

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

0

Aqui está um exemplo bonito de impressão tentando verificar a impressão digital SHA256. Fiz o download do gpg4win v3.0.3 usando o PowerShell v4 (requer Get-FileHash).

Faça o download do pacote em https://www.gpg4win.org/download.html , abra o PowerShell, pegue o hash na página de download e execute:

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

Resultado:

Hash matches for file gpg4win-3.0.3.exe

0

Aqui está um exemplo de comando de uma linha com ambos computando a soma de verificação adequada do arquivo , como você acabou de baixar, e a compara com a soma de verificação publicada do original.

Por exemplo, escrevi um exemplo para downloads do projeto Apache JMeter . Nesse caso, você tem:

  1. arquivo binário baixado
  2. soma de verificação do original publicada em file.md5 como uma sequência no formato:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Em seguida, usando este comando do PowerShell, você pode verificar a integridade do arquivo baixado:

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

Resultado:

True

Explicação:

O primeiro operando do -eqoperador é o resultado da computação da soma de verificação para o arquivo:

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

O segundo operando é o valor publicado da soma de verificação. Primeiramente, obtemos o conteúdo do arquivo.md5, que é uma string e, em seguida, extraímos o valor do hash com base no formato da string:

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

O arquivo e o arquivo.md5 devem estar na mesma pasta para este comando funcionar.


0

Isto é o que eu uso para obter um valor de 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 onde você copiou o código do PowerShell? https://communary.net/ ?
— Peter Mortensen

0

Aqui está o trecho que estou usando para obter o MD5 para uma determinada sequência:

$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")}) 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.