Get-Hash, a powershell hash function
I needed a hash function that I could pass a text string or a file to compute its hash (MD5, SHA1, etc…). But unfortunately Powershell hasn’t got one, so I started to look for alternatives:
- There’s a Get-Hash cmdlet (function embedded in a DLL written in C#) in PowerShell Community Extensions (PSCX) module.
I found two small tools command-line tools:
- The File Checksum Integrity Verifier (FCIV) is a Microsoft unsupported command-prompt utility that computes and verifies cryptographic hash, MD5 or SHA-1, values of files. Example: fciv.exe -sha1 myfile.txt
- GNU sha1sum. Example: sha1sum mapais.txt
There’s an interesting post called Using Powershell for MD5 Checksums in Brian Hartsock’s Blog that explains how to calculate directly in Powershell using NET Framework classes.
Any of these options exactly matched my needs:
- PSCX is an amazing module, but I didn’t want to install it in production servers just to use one cmdlet.
- The two small tools do they work without flawness, althought I prefer to have as less external applications as possible. I should parse the result and I prefer to have everything in Powershell.
- Brian Hartsock’s post is a good point of start. I only misses the possibility to compute file’s hashes.
So based on Brian Hartsock’s post I implemented this function for Powershell 2.0 (because I use parameter definition and try…catch in it) that gets the hash value of a file or a text string. It uses HashAlgorithm Class and FileStream Class. Both classes are supported since NET Framework 1.0.
The Get-Hash function
The following code can also be downloaded from my Github.
<#
.SYNOPSIS
Gets the hash value of a file or string
.DESCRIPTION
Gets the hash value of a file or string
It uses System.Security.Cryptography.HashAlgorithm (http://msdn.microsoft.com/en-us/library/system.security.cryptography.hashalgorithm.aspx)
and FileStream Class (http://msdn.microsoft.com/en-us/library/system.io.filestream.aspx)
Based on: http://blog.brianhartsock.com/2008/12/13/using-powershell-for-md5-checksums/ and some ideas on Microsoft Online Help
Be aware, to avoid confusions, that if you use the pipeline, the behaviour is the same as using -Text, not -File
.PARAMETER File
File to get the hash from.
.PARAMETER Text
Text string to get the hash from
.PARAMETER Algorithm
Type of hash algorithm to use. Default is SHA1
.EXAMPLE
C:\PS> Get-Hash "hello_world.txt"
Gets the SHA1 from myFile.txt file. When there's no explicit parameter, it uses -File
.EXAMPLE
Get-Hash -File "C:\temp\hello_world.txt"
Gets the SHA1 from myFile.txt file
.EXAMPLE
C:\PS> Get-Hash -Algorithm "MD5" -Text "Hello Wold!"
Gets the MD5 from a string
.EXAMPLE
C:\PS> "Hello Wold!" | Get-Hash
We can pass a string throught the pipeline
.EXAMPLE
Get-Content "c:\temp\hello_world.txt" | Get-Hash
It gets the string from Get-Content
.EXAMPLE
Get-ChildItem "C:\temp\*.txt" | %{ Write-Output "File: $($_) has this hash: $(Get-Hash $_)" }
This is a more complex example gets the hash of all "*.tmp" files
.NOTES
DBA daily stuff (http://dbadailystuff.com) by Josep Martínez Vilà
Licensed under a Creative Commons Attribution 3.0 Unported License
.LINK
Original post: https://dbadailystuff.com/2013/03/11/get-hash-a-powershell-hash-function/
#>
function Get-Hash
{
Param
(
[parameter(Mandatory=$true, ValueFromPipeline=$true, ParameterSetName="set1")]
[String]
$text,
[parameter(Position=0, Mandatory=$true,
ValueFromPipeline=$false, ParameterSetName="set2")]
[String]
$file = "",
[parameter(Mandatory=$false, ValueFromPipeline=$false)]
[ValidateSet("MD5", "SHA", "SHA1", "SHA-256", "SHA-384", "SHA-512")]
[String]
$algorithm = "SHA1"
)
Begin
{
$hashAlgorithm = [System.Security.Cryptography.HashAlgorithm]::Create($algorithm)
}
Process
{
$md5StringBuilder = New-Object System.Text.StringBuilder 50
$ue = New-Object System.Text.UTF8Encoding
if ($file){
try {
if (!(Test-Path -literalpath $file)){
throw "Test-Path returned false."
}
}
catch {
throw "Get-Hash - File not found or without permisions: [$file]. $_"
}
try {
[System.IO.FileStream]$fileStream = [System.IO.File]::Open($file, [System.IO.FileMode]::Open);
$hashAlgorithm.ComputeHash($fileStream) |
% { [void] $md5StringBuilder.Append($_.ToString("x2")) }
}
catch {
throw "Get-Hash - Error reading or hashing the file: [$file]"
}
finally {
$fileStream.Close()
$fileStream.Dispose()
}
}
else {
$hashAlgorithm.ComputeHash($ue.GetBytes($text)) |
% { [void] $md5StringBuilder.Append($_.ToString("x2")) }
}
return $md5StringBuilder.ToString()
}
}
Some examples how to call it
Here are some examples on how to use Get-Hash. Note that node.exe is a binary file.
Write-Output "`nSome examples how to call it:"
Get-Hash "c:\temp\myScriptFile.sql"
Get-Hash "c:\temp\br[a{ets.txt"
Get-Hash "c:\temp\node.exe"
Get-Hash -Algorithm "MD5" -Text "A MD5 checksum!"
Write-Output "`nFour hello world examples that return the same hash value:"
Get-Hash "c:\temp\hello_world.txt"
"Hello Wold!" | Get-Hash
Get-Hash -Text "Hello Wold!"
Get-Content "c:\temp\hello_world.txt" | Get-Hash
Get-ChildItem "C:\temp\*world*.txt" |
%{ Write-Output "File: $($_) has this hash: $(Get-Hash $_)" }