236

I would like to calculate an MD5 checksum of some content. How do I do this in PowerShell?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Luke101
  • 63,072
  • 85
  • 231
  • 359

20 Answers20

420

Starting in PowerShell version 4, this is easy to do for files out of the box with the Get-FileHash cmdlet:

Get-FileHash <filepath> -Algorithm MD5

This is certainly preferable since it avoids the problems the solution for older PowerShell offers as identified in the comments (uses a stream, closes it, and supports large files).

If the content is a string:

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

For older PowerShell version

If the content is a file:

$someFilePath = "C:\foo.txt"
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes($someFilePath)))
ndemou
  • 4,691
  • 2
  • 30
  • 33
vcsjones
  • 138,677
  • 31
  • 291
  • 286
  • 15
    `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."` As a Linux guy new to Powershell, I'm very annoyed with the struggles I'm having getting an md5 sum, which would be simply `md5sum file.ext` on Linux. – StockB Feb 12 '13 at 01:52
  • 1
    @StockB Keith's answer below is probably going to handle this better. I agree, there are some shortcomings with powershell. – vcsjones Feb 12 '13 at 14:13
  • 7
    I have vanilla PowerShell installed with no extensions, so I broke down and downloaded a command-line md5sum clone instead, which works great. I want to like Microsoft's stuff, but I just can't. – StockB Feb 12 '13 at 18:56
  • 25
    @StockB vcsjones's method is not buffered... = very memory demanding for large files. I suggest you work with streams: `$hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)))` This gives you **low memory usage** and **no 2GB limit**. – Davor Josipovic Apr 07 '13 at 12:32
  • 23
    @davor that keeps the stream open for an indeterminate period of time, so you can't delete the file until Powershell is closed. `$stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)` then `$hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))` then `$stream.Close()` – Joe Amenta Apr 25 '14 at 11:19
  • @StockB Though I'm a happy Windows developer, I feel with you. While Windows has grown to be a great development platform, some basic things are still unbelievably cumbersome compared to Linux / Unix. Scripting and automation is still a major PITA, even though PowerShell was meant to fill that gap. – chris Aug 07 '14 at 08:25
  • @stockb I think Windows is one throwaway text-piping commandline utility away from being being everyone's favorite platform to automate. Or maybe one thousand. Or maybe one package manager? I don't know, but this has little to do with PowerShell, which wraps executables just fine. – nik.shornikov Nov 20 '15 at 00:05
  • Powershell does not seem to work with shadow copy paths. Had to go with `certutil -hashfile "$path" MD5`. `Get-FileHash` just does nothing. `File::Open` returns `Paths that begin with \\?\GlobalRoot are internal to the kernel and should not be opened by managed applications.` as error message (good idea to disallow that in a system configuration language). – UrOni May 22 '16 at 16:32
  • Then will it hurt the file if I'm verifying ISO file due to large file size? (~2GiB) – Andrew.Wolphoe Feb 06 '18 at 09:55
  • @Munucial the last option will not using `Get-FileHash`. – vcsjones Feb 06 '18 at 14:35
  • its works, i can use "Get-FileHash -Algorithm md5 my/docs/folder/*" for get md5 for all files in folder. – Sergio Perez Feb 22 '21 at 14:04
58

If you are using the PowerShell Community Extensions there is a Get-Hash commandlet that will do this easily:

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


Algorithm: MD5


Path       :
HashString : E42B054623B3799CB71F0883900F2764
HairOfTheDog
  • 2,489
  • 2
  • 29
  • 35
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 13
    Get-Hash comes from PowerShell Community Extensions. When you can't or won't use the package they've added a cmdlet `Get-FileHash` in vanilla PowerShell 4.0. Vide [TechNet](http://technet.microsoft.com/en-us/library/dn520872.aspx). – Tomasz Cudziło Apr 24 '14 at 18:36
  • Note that this (and probably most PS solutions) encodes the string as UTF-16 (little-endian?). – Christian Mann Jun 21 '17 at 03:00
  • The link to PowerShell Community Extensions redirects to the CodePlex archive (CodePlex closed down in 2017). Perhaps change to the [GitHub one](https://github.com/Pscx/Pscx)? (Is the new master location on GitHub?) – Peter Mortensen Nov 03 '19 at 11:42
20

Here's a function I use that handles relative and absolute paths:

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

Thanks to @davor above for the suggestion to use Open() instead of ReadAllBytes() and to @jpmc26 for the suggestion to use a finally block.

David
  • 1,157
  • 2
  • 12
  • 19
19

Here are the two lines, just change "hello" in line #2:

PS C:\> [Reflection.Assembly]::LoadWithPartialName("System.Web")
PS C:\> [System.Web.Security.FormsAuthentication]::HashPasswordForStoringInConfigFile("hello", "MD5")
Andy Arismendi
  • 50,577
  • 16
  • 107
  • 124
AvkashChauhan
  • 20,495
  • 3
  • 34
  • 65
  • 1
    The result of this does not equal the output I get with the accepted answer. It computes the hash of the STRING "hello", not of a FILE that would be defined by any path that I replace "hello" with, correct? – RobertG Nov 18 '14 at 09:42
  • 3
    True, but OP didn't ask for a file, and I came here looking for string solution – Chris F Carroll Oct 17 '18 at 17:12
14

Another built-in command that's long been installed in Windows by default dating back to 2003 is Certutil, which of course can be invoked from PowerShell, too.

CertUtil -hashfile file.foo MD5

(Caveat: MD5 should be in all caps for maximum robustness)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
danekan
  • 462
  • 4
  • 7
12

As stated in the accepted answer, Get-FileHash is easy to use with files, but it is also possible to use it with strings. For text encoded in UTF-8:

$s = "asdf"
Get-FileHash -InputStream ([System.IO.MemoryStream]::New([System.Text.Encoding]::UTF8.GetBytes($s)))
ᄂ ᄀ
  • 5,669
  • 6
  • 43
  • 57
wensveen
  • 783
  • 10
  • 20
12

PowerShell One-Liners (string to 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("-","")
YourWishIsMine
  • 121
  • 1
  • 5
10

There are a lot of examples online using ComputeHash(). My testing showed this was very slow when running over a network connection. The snippet below runs much faster for me, however your mileage may vary:

$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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cmcginty
  • 113,384
  • 42
  • 163
  • 163
  • 1
    You method overcomes the 2Gb limit of ReadAllBytes from other answers, which is exactly what I needed. – Jay Mar 18 '17 at 19:02
  • What does the backtick on the `write-progress` line do? The syntax highlighter doesn't seem to like it. – mwfearnley Dec 01 '17 at 16:14
  • 1
    @mwfearnley The backtick enables line continuation. https://blogs.technet.microsoft.com/heyscriptingguy/2015/06/19/powertip-line-continuation-in-powershell/ – cmcginty Dec 02 '17 at 21:03
7

There is now a Get-FileHash function which is very handy.

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

Just change SHA384 to MD5.

The example is from the official documentation of PowerShell 5.1. The documentation has more examples.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
6

This site has an example: Using Powershell for MD5 Checksums. It uses the .NET framework to instantiate an instance of the MD5 hash algorithm to calculate the hash.

Here's the code from the article, incorporating Stephen's comment:

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()
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
neontapir
  • 4,698
  • 3
  • 37
  • 52
  • 1
    Good except it doesn't work for readonly files! It needs $stream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read) – Stephen Connolly May 22 '13 at 15:12
  • 1
    If the link ever dies, the answer will be quite useless. http://stackoverflow.com/help/how-to-answer – I'm with Monica Oct 28 '13 at 14:26
  • 1
    In response to what I presume was your downvote, I cut and pasted the code from the article here. I didn't do that last year, because I felt it was plagiarism. Adding Stephen's read-only adaptation made me feel it was worth posting. – neontapir Oct 28 '13 at 18:24
  • @neontapir just to say: posting something verbatim (or with adaptations) is only plagiarism if you don't acknowledge the source. Copyright (legally or morally) is a separate issue, but I wouldn't tend to worry about that with most code snippets. – mwfearnley Apr 09 '20 at 09:47
4

This becomes a one-liner if you download File Checksum Integrity Verifier (FCIV) from Microsoft.

I downloaded FCIV from here: Availability and description of the File Checksum Integrity Verifier utility

Run the following command. I had ten files to check.

Get-ChildItem WTAM*.tar | % {.\fciv $_.Name}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RonDBA
  • 76
  • 3
2

Sample for right-click menu option as well:

[HKEY_CLASSES_ROOT\*\shell\SHA1 PS check\command]
@="C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe -NoExit -Command Get-FileHash -Algorithm SHA1 '%1'"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Niklas E
  • 21
  • 1
2

Here is the snippet that I am using to get the MD5 for a given string:

$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")}) 
Carsten
  • 1,612
  • 14
  • 21
1

This will return an MD5 hash for a file on a remote computer:

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
  • 21
  • 3
0

Here is a pretty print example attempting to verify the SHA256 fingerprint. I downloaded gpg4win v3.0.3 using PowerShell v4 (requires Get-FileHash).

Download the package from https://www.gpg4win.org/download.html, open PowerShell, grab the hash from the download page, and run:

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

Output:

Hash matches for file gpg4win-3.0.3.exe
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Thomas BDX
  • 2,632
  • 2
  • 27
  • 31
0

Here is a one-line-command example with both computing the proper checksum of the file, like you just downloaded, and comparing it with the published checksum of the original.

For instance, I wrote an example for downloadings from the Apache JMeter project. In this case you have:

  1. downloaded binary file
  2. checksum of the original which is published in file.md5 as one string in the format:

3a84491f10fb7b147101cf3926c4a855 *apache-jmeter-4.0.zip

Then using this PowerShell command, you can verify the integrity of the downloaded file:

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

Output:

True

Explanation:

The first operand of -eq operator is a result of computing the checksum for the file:

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

The second operand is the published checksum value. We firstly get content of the file.md5 which is one string and then we extract the hash value based on the string format:

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

Both file and file.md5 must be in the same folder for this command work.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Egor B Eremeev
  • 982
  • 11
  • 20
0

This is what I use to get a consistent hash value:

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()
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user2529654
  • 71
  • 1
  • 5
0
(
    [System.Security.Cryptography.MD5CryptoServiceProvider]::new().ComputeHash(
        [System.Text.UTF8Encoding]::new().GetBytes($yourText)
    ) `
    | %{ [Convert]::ToString($_, 16) }
) -join ''

$yourText = 'hello' yields 5d41402abc4b2a76b9719d911017c592

Hashbrown
  • 12,091
  • 8
  • 72
  • 95
0

Team! Look at my hash calculation function.

Function Get-StringHash {
<#
    .DESCRIPTION
        Get string persistant hash.        
#>
    [OutputType([string])]
    [CmdletBinding()]
    Param(
        [Parameter( Mandatory = $True, Position = 0, HelpMessage = "String to calculate hash." )]
        [string] $String,
        [Parameter( Mandatory = $false, Position = 0, HelpMessage = "String encoding." )]
        [ValidateSet( 'UTF8' )]
        [string] $StringEncoding = 'UTF8',
        [Parameter( Mandatory = $false, Position = 2, HelpMessage = "Hash algoritm." )]
        [ValidateSet( 'md5', 'sha256', 'sha512' )]
        [string] $Algoritm = 'sha256'
    )
    try {
        #region functions
        #endregion

        $Result = $null

        switch ( $Algoritm ) {
            'md5' {  
                $HashProvider = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
            }
            'sha256' {  
                $HashProvider = New-Object -TypeName System.Security.Cryptography.SHA256CryptoServiceProvider
            }
            'sha512' {  
                $HashProvider = New-Object -TypeName System.Security.Cryptography.SHA512CryptoServiceProvider
            }
            Default {}
        }

        switch ( $StringEncoding ) {
            'UTF8' {  
                $Encoding = New-Object -TypeName System.Text.UTF8Encoding
            }
            Default {}
        }
        
        
        $Result = [System.BitConverter]::ToString( $HashProvider.ComputeHash( $Encoding.GetBytes( $String ) )).replace('-','')

    }
    catch {
        Get-ErrorReporting -Trap $_
    }

    return $Result
}

$String   = 'Some text'
$Algoritm = 'MD5'

$Hash = Get-StringHash -String $String -Algoritm $Algoritm

write-host "$String has $Algoritm hash $hash"
0

using @YourWishIsMine answer, I created a simple function that supports all the algorithms for a string input. Because the types follow a specific naming convention, this can be easily extended to future algorithms by simply adding to the "ValidateSet" without any further code changes.

I also added pipeline support as well.

function ConvertTo-HashString
{
    param (
            [Parameter(Mandatory=$true,ValueFromPipeLine=$true)][string]$value, 
            [ValidateSet("MD5","SHA1","SHA256","SHA384","SHA512")][string]$Algorithm="SHA256"
            )
    process {
        foreach ($v in $value)
        {
            $TypeName = "System.Security.Cryptography.{0}CryptoServiceProvider" -f $Algorithm
            #check the algorithm to ensure its a valid type, for ValidateSet
            if (-not ($typename -as [Type])) {
                throw "Invalid Algorithm $Algorithm"
            }
            $Bytes = [System.Text.Encoding]::UTF8.GetBytes($v)
            $hash = ([System.BitConverter]::ToString((New-Object -TypeName $TypeName).ComputeHash($Bytes))).Replace("-","")

            write-output $hash;
        }
    }
}

example usage:

ConvertTo-HashString -value 'hello world' -Algorithm sha256
B94D27B9934D3E08A52E52D7DA7DABFAC484EFE37A5380EE9088F7ACE2EFCDE9

ConvertTo-HashString -value 'hello world' -Algorithm sha512
309ECC489C12D6EB4CC40F50C902F2B4D0ED77EE511A7C7A9BCD3CA86D4CD86F989DD35BC5FF499670DA34255B45B0CFD830E81F605DCF7DC5542E93AE9CD76F

@('a','b','c') | ConvertTo-HashString -Algorithm SHA256
CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB
3E23E8160039594A33894F6564E1B1348BBD7A0088D42C4ACB73EEAED59C009D
2E7D2C03A9507AE265ECF5B5356885A53393A2029D241394997265A1A25AEFC6
Justin
  • 1,303
  • 15
  • 30