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.