Как получить контрольную сумму MD5 в PowerShell

179

Я хотел бы рассчитать контрольную сумму MD5 для некоторого контента. Как мне сделать это в PowerShell?

Luke101
источник
3
Что такое "некоторый контент"? файл? строка?
vcsjones

Ответы:

326

Если содержимое является строкой:

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

Если содержимое файла:

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

Начиная с PowerShell версии 4, это легко сделать для файлов из коробки с помощью Get-FileHashкомандлета:

Get-FileHash <filepath> -Algorithm MD5

Это, безусловно, предпочтительнее, поскольку позволяет избежать проблем, которые предлагает первое решение, как указано в комментариях (использует поток, закрывает его и поддерживает большие файлы).

vcsjones
источник
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."Как новичок в Powershell, работающий в Linux, я очень недоволен борьбой, которую я испытываю, получая сумму md5, которая была бы просто md5sum file.extв Linux.
13
@StockB Ответ Кейта ниже, вероятно, справится с этим лучше. Я согласен, есть некоторые недостатки в PowerShell.
vcsjones
5
У меня установлена ​​ванильная оболочка PowerShell без расширений, поэтому я сломался и вместо этого скачал клон командной строки md5sum, который прекрасно работает. Я хочу любить вещи Microsoft, но я просто не могу.
StockB
23
Метод @StockB vcsjones не буферизуется ... = очень большой объем памяти для больших файлов. Я предлагаю вам работать с потоками: $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))это дает вам низкое использование памяти и не ограничивает 2 ГБ .
Давор Йосипович
20
@davor, который сохраняет поток открытым в течение неопределенного периода времени, поэтому вы не можете удалить файл, пока Powershell не будет закрыт. $stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)то $hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))тогда$stream.Close()
Джо Amenta
57

Если вы используете PowerShell Community Extensions, есть командлет Get-Hash, который сделает это легко:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764
Кит Хилл
источник
10
Get-Hash происходит от расширений сообщества PowerShell. Когда вы не можете или не хотите использовать пакет, они добавили командлет Get-FileHashв vanilla PowerShell 4.0. Видео TechNet .
Томаш Кудзило
Обратите внимание, что это (и, вероятно, большинство решений PS) кодирует строку как UTF-16 (little-endian?).
Кристиан Манн
Ссылка на PowerShell Community Extensions перенаправляет в архив CodePlex (CodePlex закрыт в 2017 году). Возможно, перейдите на GitHub ? (Является ли новый мастер локации на GitHub?)
Питер Мортенсен
16

Вот две строки, просто измените «привет» в строке № 2:

PS C:\> [Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\> [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("hello", "MD5")
AvkashChauhan
источник
1
Результат этого не равен выводу, который я получаю с принятым ответом. Он вычисляет хеш STRING "привет", а не ФАЙЛА, который будет определен любым путем, которым я заменяю "привет", правильно?
RobertG
1
Правда, но OP не просил файл, и я пришел сюда в поисках строкового решения
Крис Ф. Кэрролл,
16

Вот функция, которую я использую, которая обрабатывает относительные и абсолютные пути:

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

Спасибо @davor выше за предложение использовать Open () вместо ReadAllBytes () и @ jpmc26 за предложение использовать блок finally.

Дэвид
источник
2
Этот подход лучше IMHO, чем vcsjones и Keith, потому что он может принимать входные файлы размером более 2 ГБ и не требует никаких расширений или PowerShell 4.0.
Чираг Бхатия - chirag64
1
DisposeВызов должен быть в finallyблоке.
jpmc26
12

Еще одна встроенная команда, которая долгое время была установлена ​​в Windows по умолчанию начиная с 2003 года, - это Certutil , которая, конечно же, также может вызываться из PowerShell.

CertUtil -hashfile file.foo MD5

(Предостережение: MD5 должен быть во всех заглавных буквах для максимальной надежности)

danekan
источник
1
Это хороший вариант, когда FipsAlgorithmPolicyвключен.
Уильям Джон Холден
9

Есть много примеров онлайн с использованием ComputeHash (). Мои тесты показали, что это было очень медленно при работе через сетевое соединение. Ниже приведен фрагмент кода, который работает намного быстрее, однако ваш пробег может отличаться:

$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
источник
1
Ваш метод преодолевает лимит ReadAllBytes в 2 Гб из других ответов, что именно то, что мне было нужно.
Jay
Что делает обратный удар на write-progressлинии? Подсветка синтаксиса, кажется, не нравится.
mwfearnley
1
@mwfearnley Обратный тик позволяет продолжить линию. blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
cmcginty
6

На этом сайте есть пример: Использование Powershell для контрольных сумм MD5 . Он использует платформу .NET для создания экземпляра алгоритма хеширования MD5 для вычисления хеша.

Вот код из статьи, включающий комментарий Стивена:

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()
neontapir
источник
1
Хорошо, за исключением того, что он не работает для файлов только для чтения! Для этого требуется $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: Read)
Стивен Коннолли
1
Если ссылка когда-либо умрет, ответ будет совершенно бесполезным. stackoverflow.com/help/how-to-answer
Я с Моникой
1
В ответ на то, что, как я полагаю, вы поняли, я вырезал и вставил код из статьи здесь. Я не делал этого в прошлом году, потому что я чувствовал, что это был плагиат. Добавление адаптации Стивена только для чтения заставило меня почувствовать, что это стоит опубликовать.
Неонтапир
@neontapir просто сказать: размещение чего-то дословного (или с адаптациями) - это всего лишь плагиат, если вы не признаете источник. Авторское право (юридически или морально) является отдельной проблемой, но я бы не стал беспокоиться об этом с большинством фрагментов кода.
Mwfearnley
6

Как указано в принятом ответе, Get-FileHashего легко использовать с файлами, но его также можно использовать со строками:

$s = "asdf"
Get-FileHash -InputStream ([System.IO.MemoryStream]::New([System.Text.Encoding]::ASCII.GetBytes($s)))
wensveen
источник
5

Теперь есть функция Get-FileHash, которая очень удобна.

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

Просто измени SHA384на MD5.

Пример взят из официальной документации PowerShell 5.1 . В документации есть больше примеров.

Браулио Дж. Солано
источник
3

PowerShell One-Liners (строка в хэш)

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("-","")
YourWishIsMine
источник
1

Это вернет хеш MD5 для файла на удаленном компьютере:

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
источник
1

Пример для опции меню правой кнопкой мыши также:

[HKEY_CLASSES_ROOT\*\shell\SHA1 PS check\command]
@="C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -NoExit -Command Get-FileHash -Algorithm SHA1 '%1'"
Никлас Е
источник
0

Вот прекрасный пример печати, пытающийся проверить отпечаток SHA256. Я скачал gpg4win v3.0.3 с помощью PowerShell v4 (требуется Get-FileHash).

Загрузите пакет с https://www.gpg4win.org/download.html , откройте PowerShell, возьмите хеш со страницы загрузки и запустите:

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

Вывод:

Hash matches for file gpg4win-3.0.3.exe
Томас
источник
0

Вот пример однострочной команды с вычислением правильной контрольной суммы файла , как вы только что скачали, и сравнивает ее с опубликованной контрольной суммой оригинала.

Например, я написал пример для загрузки из проекта Apache JMeter . В этом случае у вас есть:

  1. скачанный бинарный файл
  2. контрольная сумма оригинала, который публикуется в file.md5 в виде одной строки в формате:

3a84491f10fb7b147101cf3926c4a855 * apache-jmeter-4.0.zip

Затем с помощью этой команды PowerShell вы можете проверить целостность загруженного файла:

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

Вывод:

True

Объяснение:

Первый операнд -eqоператора является результатом вычисления контрольной суммы для файла:

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

Вторым операндом является опубликованное значение контрольной суммы. Сначала мы получаем содержимое файла file.md5, представляющего собой одну строку, а затем извлекаем значение хеш-функции на основе формата строки:

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

И файл, и файл.md5 должны находиться в одной папке для работы этой команды.

Егор Б Еремеев
источник
0

Это то, что я использую для получения согласованного значения хэша:

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
источник
Откуда вы скопировали код PowerShell? https://communary.net/ ?
Питер Мортенсен
0

Вот фрагмент, который я использую, чтобы получить MD5 для данной строки:

$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")}) 
Питер
источник