PowerShell has a function Get-FileHash to compute the hash value for a file by using a specified hash algorithm. For example, to calculate SHA1 hash code for a file:
Get-FileHash -Path "D:\Software\test.ovf" -Algorithm SHA1
You can also check other algorithms like MD5, SHA256 etc.
PS D:\Software> Get-Command Get-FileHash
CommandType Name Version Source
----------- ---- ------- ------
Function Get-FileHash 3.1.0.0 Microsoft.PowerShell.Utility
To see the definition of the function:
PS D:\Software> (Get-Command Get-FileHash).definition
[CmdletBinding(DefaultParameterSetName = "Path", HelpURI = "https://go.microsoft.com/fwlink/?LinkId=517145")]
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", "MACTripleDES", "MD5", "RIPEMD160")]
[System.String]
$Algorithm="SHA256"
)
begin
{
# Construct the strongly-typed crypto object
# First see if it has a FIPS algorithm
$hasherType = "System.Security.Cryptography.${Algorithm}CryptoServiceProvider" -as [Type]
if ($hasherType)
{
$hasher = $hasherType::New()
}
else
{
# Check if the type is supported in the current system
$algorithmType = "System.Security.Cryptography.${Algorithm}" -as [Type]
if ($algorithmType)
{
if ($Algorithm -eq "MACTripleDES")
{
$hasher = $algorithmType::New()
}
else
{
$hasher = $algorithmType::Create()
}
}
else
{
$errorId = "AlgorithmTypeNotSupported"
$errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument
$errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::AlgorithmTypeNotSupported -f $Algorithm
$exception = [System.InvalidOperationException]::New($errorMessage)
$errorRecord = [System.Management.Automation.ErrorRecord]::New($exception, $errorId, $errorCategory, $null)
$PSCmdlet.ThrowTerminatingError($errorRecord)
}
}
function GetStreamHash
{
param(
[System.IO.Stream]
$InputStream,
[System.String]
$RelatedPath,
[System.Security.Cryptography.HashAlgorithm]
$Hasher)
# Compute file-hash using the crypto object
[Byte[]] $computedHash = $Hasher.ComputeHash($InputStream)
[string] $hash = [BitConverter]::ToString($computedHash) -replace '-',''
if ($RelatedPath -eq $null)
{
$retVal = [PSCustomObject] @{
Algorithm = $Algorithm.ToUpperInvariant()
Hash = $hash
}
}
else
{
$retVal = [PSCustomObject] @{
Algorithm = $Algorithm.ToUpperInvariant()
Hash = $hash
Path = $RelatedPath
}
}
$retVal.psobject.TypeNames.Insert(0, "Microsoft.Powershell.Utility.FileHash")
$retVal
}
}
process
{
if($PSCmdlet.ParameterSetName -eq "Stream")
{
GetStreamHash -InputStream $InputStream -RelatedPath $null -Hasher $hasher
}
else
{
$pathsToProcess = @()
if($PSCmdlet.ParameterSetName -eq "LiteralPath")
{
$pathsToProcess += Resolve-Path -LiteralPath $LiteralPath | Foreach-Object ProviderPath
}
if($PSCmdlet.ParameterSetName -eq "Path")
{
$pathsToProcess += Resolve-Path $Path | Foreach-Object ProviderPath
}
foreach($filePath in $pathsToProcess)
{
if(Test-Path -LiteralPath $filePath -PathType Container)
{
continue
}
try
{
# Read the file specified in $FilePath as a Byte array
[system.io.stream]$stream = [system.io.file]::OpenRead($filePath)
GetStreamHash -InputStream $stream -RelatedPath $filePath -Hasher $hasher
}
catch [Exception]
{
$errorMessage = [Microsoft.PowerShell.Commands.UtilityResources]::FileReadError -f $FilePath, $_
Write-Error -Message $errorMessage -Category ReadError -ErrorId "FileReadError" -TargetObject $FilePath
return
}
finally
{
if($stream)
{
$stream.Dispose()
}
}
}
}
}
To check a series of files under certain directory:
Get-ChildItem -File |where {$_.Name -notlike '*dbg'}|ForEach-Object {Get-FileHash -Path $_ -Algorithm MD5}
However you may see an error like the following when calculating MD5:
Exception calling ".ctor" with "0" argument(s): "This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms."
At
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\Microsoft.PowerShell.Utility\Microsoft.PowerShell.Utility.psm1:31
char:13
That’s because the computer where you run the PowerShell has FIPS enabled. You can confirm it’s enabled with:
PS D:\> Get-ItemProperty -Path Registry::HKLM\System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy
Enabled : 1
PSPath : Microsoft.PowerShell.Core\Registry::HKLM\System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy
PSParentPath : Microsoft.PowerShell.Core\Registry::HKLM\System\CurrentControlSet\Control\Lsa
PSChildName : FIPSAlgorithmPolicy
PSProvider : Microsoft.PowerShell.Core\Registry
Or if you have a PowerShell drive namedHKLM mapped to registry: HKEY_LOCAL_MACHINE:
PS D:\> Get-PSDrive
Name Used (GB) Free (GB) Provider Root CurrentLocation
---- --------- --------- -------- ---- ---------------
Alias Alias
C 51.09 48.37 FileSystem C:\ Windows\system32
Cert Certificate \
D 104.23 919.77 FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Variable Variable
WSMan WSMan
Z FileSystem Z:\
PS D:\> Get-ItemProperty -Path HKLM:\System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy
Enabled : 1
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa
PSChildName : FIPSAlgorithmPolicy
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
.NET has the property AllowOnlyFipsAlgorithms enabled:
PS D:\> [System.Security.Cryptography.Cryptoconfig]::AllowOnlyFipsAlgorithms
True
As a comparison, you can create an SHA256 object, but it will fail when creating an MD5 object:
PS D:\> $md5 = [System.Security.Cryptography.MD5]::Create()
Exception calling "Create" with "0" argument(s): "This implementation is not part of the Windows Platform FIPS validated
cryptographic algorithms."
At line:1 char:1
+ $md5 = [System.Security.Cryptography.MD5]::Create()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : InvalidOperationException
PS D:\> $sha256 = [System.Security.Cryptography.SHA256]::Create()
PS D:\> $sha256.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False SHA256Cng System.Security.Cryptography.SHA256
If you really need to compute MD5 checksum, you might use certutil.exe as a workaround without disabling FIPS
PS D:\Software> Get-Command certutil.exe
CommandType Name Version Source
----------- ---- ------- ------
Application certutil.exe 10.0.17... C:\Windows\system32\certutil.exe
PS D:\Software> certutil.exe -hashfile .\test.ovf md5
MD5 hash of .\test.ovf: 1cab1536b160b8a6827de086852a4598
CertUtil: -hashfile command completed successfully.
References:
Thanks! Here’s my solution to live with FIPS:
function CertUtilMD5
{
[cmdletbinding()]
param([string]$filepath)
$cmdpar = @(‘-hashfile’, $filepath, ‘md5’);
$out = (&certutil.exe $cmdpar) -split “`n”;
$MD5 = $null;
[bool]$ret = ( 0 -eq $LASTEXITCODE);
$message = switch ($LASTEXITCODE)
{
0 {
Write-Verbose $out[0].Trim();
$MD5 = $out[1].Trim();
Write-Verbose $out[2].Trim();
}
default {
Write-Warning $out[0].Trim();
Write-Error $out[1].Trim();
}
}
return $MD5;
}
LikeLike