วิธีรับการตรวจสอบ MD5 ใน PowerShell


179

ฉันต้องการคำนวณMD5 checksum ของเนื้อหาบางส่วน ฉันจะทำสิ่งนี้ใน PowerShell ได้อย่างไร


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-FileHashcmdlet ทำได้ง่าย:

Get-FileHash <filepath> -Algorithm MD5

นี่เป็นวิธีที่ดีกว่าเนื่องจากจะหลีกเลี่ยงปัญหาที่โซลูชันแรกเสนอตามที่ระบุในข้อคิดเห็น (ใช้สตรีมปิดและสนับสนุนไฟล์ขนาดใหญ่)


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 ฉันรู้สึกหงุดหงิดมากกับการต่อสู้ที่ฉันได้รับผลรวม md5 ซึ่งจะเป็นเพียงแค่md5sum file.extลินุกซ์
StockB

@StockB Keith คำตอบด้านล่างนี้น่าจะจัดการได้ดีกว่านี้ ฉันเห็นด้วยมีข้อบกพร่องบางอย่างกับ 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)))นี้จะช่วยให้คุณใช้งานหน่วยความจำต่ำและไม่ จำกัด
Davor Josipovic

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()
Joe Amenta

57

หากคุณกำลังใช้ ส่วนขยายชุมชน PowerShellมี commandlet Get Hash ที่จะทำสิ่งนี้ได้อย่างง่ายดาย:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764

10
Get-Hash มาจาก PowerShell Community Extensions เมื่อคุณไม่สามารถใช้แพ็คเกจเหล่านี้ได้เพิ่ม cmdlet Get-FileHashใน vanilla PowerShell 4.0 Vide TechNet
Tomasz Cudziło

โปรดทราบว่านี่ (และอาจเป็นโซลูชัน PS ส่วนใหญ่) เข้ารหัสสตริงเป็น UTF-16 (little-endian?)
Christian Mann

ลิงก์ไปยัง PowerShell Community Extensions เปลี่ยนเส้นทางไปยังที่เก็บ CodePlex (CodePlex ปิดตัวลงในปี 2017) อาจเปลี่ยนเป็นGitHubหรือไม่ (เป็นที่ตั้งต้นแบบใหม่ใน GitHub หรือไม่)
Peter Mortensen

16

นี่คือสองบรรทัดเพียงเปลี่ยน "hello" ในบรรทัด # 2:

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

1
ผลลัพธ์ของสิ่งนี้ไม่เท่ากับผลลัพธ์ที่ฉันได้รับด้วยคำตอบที่ยอมรับ จะคำนวณแฮชของ STRING "hello" ไม่ใช่ไฟล์ที่จะกำหนดโดยเส้นทางใด ๆ ที่ฉันแทนที่ "hello" ด้วยถูกต้องหรือไม่
RobertG

1
จริง แต่ OP ไม่ขอไฟล์และฉันมาที่นี่เพื่อค้นหาวิธีแก้ปัญหาสตริง
Chris F Carroll

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 สำหรับคำแนะนำเพื่อใช้บล็อกในที่สุด


2
วิธีการนี้ดีกว่า IMHO มากกว่า vcsjones 'และ Keith เพราะสามารถรับไฟล์ที่มีขนาดใหญ่กว่า 2GB และไม่ต้องการนามสกุลหรือ PowerShell 4.0
Chirag Bhatia - chirag64

1
การDisposeโทรควรอยู่ในfinallyบล็อก
jpmc26

12

อีกคำสั่งในตัวที่ติดตั้งมานานใน Windows โดยค่าเริ่มต้นย้อนหลังไปถึงปี 2003 คือCertutilซึ่งแน่นอนว่าสามารถเรียกใช้จาก PowerShell ได้เช่นกัน

CertUtil -hashfile file.foo MD5

(Caveat: MD5 ควรอยู่ในตัวพิมพ์ใหญ่ทั้งหมดเพื่อความทนทานสูงสุด)


1
นี่เป็นตัวเลือกที่ดีเมื่อFipsAlgorithmPolicyเปิดใช้งาน
William John Holden

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

1
วิธีการของคุณจะเอาชนะขีด จำกัด ของ ReadAllBytes 2Gb จากคำตอบอื่นซึ่งเป็นสิ่งที่ฉันต้องการ
Jay

backtick บนwrite-progressสายทำอะไร เครื่องมือเน้นไวยากรณ์ดูเหมือนจะไม่ชอบ
mwfearnley

1
@mwfearnley backtick เปิดใช้งานการต่อเนื่องของบรรทัด blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/…
cmcginty

6

ไซต์นี้มีตัวอย่าง: การใช้ Powershell สำหรับการตรวจสอบ MD5Checksums ใช้กรอบงาน. NET เพื่อสร้างอินสแตนซ์ของอัลกอริทึมแฮช MD5 เพื่อคำนวณแฮช

นี่คือรหัสจากบทความซึ่งรวมข้อคิดเห็นของ 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
ดียกเว้นมันใช้ไม่ได้กับไฟล์แบบอ่านอย่างเดียว! มันต้องการ $ stream = New-Object System.IO.FileStream ($ Path, [System.IO.FileMode] :: Open, [System.IO.FileAccess] :: อ่าน)
Stephen Connolly

1
หากลิงค์เสียชีวิตคำตอบจะไร้ประโยชน์ทีเดียว stackoverflow.com/help/how-to-answer
ฉันอยู่กับโมนิก้า

1
เพื่อตอบสนองต่อสิ่งที่ฉันคิดว่าเป็น downvote ของคุณฉันตัดและวางโค้ดจากบทความที่นี่ ฉันไม่ได้ทำเช่นนั้นเมื่อปีที่แล้วเพราะฉันรู้สึกว่ามันเป็นการลอกเลียนแบบ การเพิ่มการปรับแบบอ่านอย่างเดียวของสตีเฟ่นทำให้ฉันรู้สึกว่ามันคุ้มค่ากับการโพสต์
neontapir

@neontapir เพียงเพื่อพูดว่า: การโพสต์สิ่งที่เป็นคำต่อคำ (หรือด้วยการดัดแปลง) เป็นเพียงการลอกผลงานถ้าคุณไม่ยอมรับแหล่งที่มา ลิขสิทธิ์ (ถูกต้องตามกฎหมายหรือทางศีลธรรม) เป็นปัญหาที่แยกจากกัน แต่ฉันจะไม่กังวลเกี่ยวกับเรื่องนี้กับข้อมูลโค้ดส่วนใหญ่
mwfearnley

6

ตามที่ระบุไว้ในคำตอบที่ยอมรับGet-FileHashใช้งานง่ายกับไฟล์ แต่ก็สามารถใช้กับสตริงได้:

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

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

การเปลี่ยนแปลงเพียงเพื่อSHA384MD5

ตัวอย่างจากเอกสารอย่างเป็นทางการของ PowerShell 5.1 เอกสารมีตัวอย่างเพิ่มเติม


3

สิ่งนี้จะกลายเป็นหนึ่งซับไลน์ถ้าคุณดาวน์โหลด File Checksum Integrity Verifier (FCIV) จาก Microsoft

ฉันดาวน์โหลด FCIV จากที่นี่: ความพร้อมใช้งานและคำอธิบายของยูทิลิตี้ตัวตรวจสอบความถูกต้องของไฟล์ Checksum Integrity Verifier

เรียกใช้คำสั่งต่อไปนี้ ฉันมีสิบไฟล์เพื่อตรวจสอบ

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

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

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

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

นี่คือตัวอย่างหนึ่งบรรทัดคำสั่งที่มีทั้งการคำนวณการตรวจสอบที่เหมาะสมของไฟล์เช่นคุณเพิ่งดาวน์โหลดและเปรียบเทียบกับการตรวจสอบการเผยแพร่ของต้นฉบับ

ยกตัวอย่างเช่นผมเขียนตัวอย่างสำหรับdownloadings จากโครงการ ในกรณีนี้คุณมี:

  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ตัวดำเนินการเป็นผลลัพธ์ของการคำนวณ checksum สำหรับไฟล์:

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

ทั้งไฟล์และfile.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()
}

คุณคัดลอกรหัส 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")}) 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.