Skip to content

Instantly share code, notes, and snippets.

@advanceboy
Last active June 3, 2022 07:42
Show Gist options
  • Save advanceboy/9a4200eb8e06cb9fda5326bf41e338cb to your computer and use it in GitHub Desktop.
Save advanceboy/9a4200eb8e06cb9fda5326bf41e338cb to your computer and use it in GitHub Desktop.
As an alternative to Get-FileHash, this script computes the hash value with multiple algorithms at the same time.
#Requires -Version 5.0
[CmdletBinding(DefaultParameterSetName = "Path")]
param(
[Parameter(Mandatory, ParameterSetName="Path", Position = 0)]
[System.String[]]
$Path,
[Parameter(Mandatory, ParameterSetName="LiteralPath", ValueFromPipelineByPropertyName = $true)]
[Alias("PSPath")]
[System.String[]]
$LiteralPath,
[Parameter(Mandatory, ParameterSetName="Stream")]
[System.IO.Stream]
$InputStream,
[ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MD5")]
[ValidateNotNullOrEmpty()]
[System.String[]]
$Algorithms=@("SHA256"),
[ValidateRange(1, 2GB)]
[int]
$BufferSize=8MB
);
begin {
Set-StrictMode -Version Latest;
trap { break; }
$algorithmTypeInfos = @();
$algorithmTypeInfos += $Algorithms | ForEach-Object {
$algorithmType = "System.Security.Cryptography.$_" -as [Type];
if (!$algorithmType) {
throw "Not Supported: $_";
}
Write-Output @{Name = $_; Type = $algorithmType };
};
$hashCoreType = Add-Type -Language CSharp -PassThru -TypeDefinition @"
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
public static class HashCore {
public static void Hash(Stream inputStream, IEnumerable<HashAlgorithm> hashers, int bufferSize) {
var bin1 = new byte[bufferSize];
var bin2 = new byte[bufferSize];
byte[] bint;
int read = 0;
var hasherArray = hashers.ToArray();
var streams = new CryptoStream[hasherArray.Length];
var waitTasks = new Task[hasherArray.Length + 1];
try {
for (var i = 0; i < hasherArray.Length; i++) {
streams[i] = new CryptoStream(Stream.Null, hasherArray[i], CryptoStreamMode.Write);
}
do {
var readTask = inputStream.ReadAsync(bin1, 0, bufferSize);
for (var i = 0; i < hasherArray.Length; i++) {
waitTasks[i] = streams[i].WriteAsync(bin2, 0, read);
}
waitTasks[hasherArray.Length] = readTask;
Task.WaitAll(waitTasks);
read = readTask.Result;
bint = bin1;
bin1 = bin2;
bin2 = bint;
} while (read > 0);
for (var i = 0; i < hasherArray.Length; i++) {
streams[i].FlushFinalBlock();
}
} finally {
foreach (var stream in streams) {
if (stream != null) {
stream.Dispose();
}
}
}
}
}
"@;
function Get-StreamHash ([System.IO.Stream]$InputStream) {
$hashers = New-Object System.Security.Cryptography.HashAlgorithm[]($algorithmTypeInfos.Length);
try {
for ($i = 0; $i -lt $algorithmTypeInfos.Length; $i++) {
$hashers[$i] = $algorithmTypeInfos[$i].Type::Create();
}
$hashCoreType::Hash($InputStream, $hashers, $BufferSize);
for ($i = 0; $i -lt $algorithmTypeInfos.Length; $i++) {
[ordered]@{Algorithm = $algorithmTypeInfos[$i].Name; Hash = [System.BitConverter]::ToString([byte[]]$hashers[$i].Hash) -replace '-',''};
}
} finally {
foreach ($hasher in $hashers) {
if ($null -ne $hasher) {
$hasher.Dispose();
}
}
}
}
}
process {
$results = @();
if ($PSCmdlet.ParameterSetName -eq 'Stream') {
$results += Get-StreamHash -InputStream $InputStream;
} else {
$filePaths = @();
if ($PSCmdlet.ParameterSetName -eq 'Path') {
$filePaths += Resolve-Path $Path | ForEach-Object -MemberName ProviderPath;
}
if ($PSCmdlet.ParameterSetName -eq 'LiteralPath') {
$filePaths += Resolve-Path -LiteralPath $LiteralPath | ForEach-Object -MemberName ProviderPath;
}
foreach ($filepath in $filePaths) {
$stream = [System.IO.File]::OpenRead($filePath);
try {
$currentResults = Get-StreamHash -InputStream $stream;
foreach ($result in $currentResults) {
$result['Path'] = $filePath;
}
$results += $currentResults;
} finally {
$stream.Dispose();
}
}
}
foreach ($result in $results) {
$retVal = [PSCustomObject]$result;
$retVal.PSObject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash");
$retVal;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment