PS: Create Hashes
This script will create checksum files for individual files or one file that contains all chacksums of a given path (including subfolders) Supported algorithms are MD5 SHA1, SHA256, SHA512. (SHA256 and SHA512 depend on the OS version you run the script on)
Requirements
- PowerShell
Usage
To run the script just call it and provide the required parameters
Parameters:
- InputPath
[STRING] Mandatory parameter that provides the source path for the archive operations - HashAlgorithm
[STRING] Parameter to change the hashing algorithm used when creating file hashes. Supported are: MD5, SHA1 (default), SHA256 and SHA512
SHA256 and SHA512 are not supported on all operating systems (tested on Windows 8 / Server 2012 and higher) - InputFileMask
[STRING] This parameter controls the input file mask and can be used to only archive files of a given file type. - LogFilePath
[STRING] Path where the log file should be created (If logging is enabled) - LogFileBaseName
[STRING] Name of the log file. This string gets appended to the date time value ( - LogFileDateTime)
Default path is the script executable directory - LogFileDateTime
[STRING] Date time formatting string that can be used to create log files on for example a daily basis (yyyyMMdd) - CreateHashForEachFile
[BOOL] Enabled by default it creates hash file for each file that gets processed. - CreateHashForAllFiles
[BOOL] Enabled by default this parameter creates a file in the input directory that holds all processed filenames and hashes - NoLogging
[BOOL] Enabled by default. This parameter can be used to prevent log file creation - DebugLogging
[BOOL] Disabled by default. This parameter can be used to enable debug logging (this increases the size of the log file)
To enable debug logging the parameter NoLogging needs to be $ false - DebugToScreen
[BOOL] Disabled by default. When enabled and DebugLogging is also enabled all information written to the log file get displayed
also to the console window. - RemoveExistingHashFiles
[BOOL] Enabled by default this parameter ensures hash files can overwrite existing hash files for the processed files
Version History:
- 1.0.0: Initial verison
- 1.0.1: license changed to MIT license; Bugfixes
Script code:
##------------------------------------------------------------------------------------------------
##
## Create-Hashes.ps1
##
## Version 1.0.1
##
##
## Copyright (c) 2016 Martin Mueller - www.sh-soft.com
##
## Permission is hereby granted, free of charge, to any person obtaining a copy of this software
## and associated documentation files (the "Software"), to deal in the Software without
## restriction, including without limitation the rights to use, copy, modify, merge, publish,
## distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
## Software is furnished to do so, subject to the following conditions:
##
## The above copyright notice and this permission notice shall be included in all copies or
## substantial portions of the Software.
##
## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
## BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
## DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## (The MIT License (MIT))
##
##------------------------------------------------------------------------------------------------
<#
.SYNOPSIS
Reads given files and creates checksums for all of them.
.DESCRIPTION
Reads given files and creates checksums for all of them.
.PARAMETER InputPath
[STRING] Mandatory parameter that provides the source path for the archive operations
.PARAMETER HashAlgorithm
[STRING] Parameter to change the hashing algorithm used when creating file hashes. Supported are: MD5, SHA1 (default), SHA256 and SHA512
SHA256 and SHA512 are not supported on all operating systems (tested on Windows 8 / Server 2012 and higher)
.PARAMETER InputFileMask
[STRING] This parameter controls the input file mask and can be used to only archive files of a given file type.
.PARAMETER LogFilePath
[STRING] Path where the log file should be created (If logging is enabled)
.PARAMETER LogFileBaseName
[STRING] Name of the log file. This string gets appended to the date time value (.PARAMETER LogFileDateTime)
Default path is the script executable directory
.PARAMETER LogFileDateTime
[STRING] Date time formatting string that can be used to create log files on for example a daily basis (yyyyMMdd)
.PARAMETER CreateHashForEachFile
[BOOL] Enabled by default it creates hash file for each file that gets processed.
.PARAMETER CreateHashForAllFiles
[BOOL] Enabled by default this parameter creates a file in the input directory that holds all processed filenames and hashes
.PARAMETER NoLogging
[BOOL] Enabled by default. This parameter can be used to prevent log file creation
.PARAMETER DebugLogging
[BOOL] Disabled by default. This parameter can be used to enable debug logging (this increases the size of the log file)
To enable debug logging the parameter NoLogging needs to be $false
.PARAMETER DebugToScreen
[BOOL] Disabled by default. When enabled and DebugLogging is also enabled all information written to the log file get displayed
also to the console window.
.PARAMETER RemoveExistingHashFiles
[BOOL] Enabled by default this parameter ensures hash files can overwrite existing hash files for the processed files
.EXAMPLE
Quick hash creation with default parameters
.\Create-Hashes.ps1 -InputPath "C:\inetpub\logs\LogFiles"
#>
#------------------------------------------------------------------------------------------------
# Parameter block
#------------------------------------------------------------------------------------------------
param(
[Parameter(Mandatory=$TRUE)]
[String] $InputPath,
[String] $HashAlgorithm="SHA1",
[String] $InputFileMask="*",
[String] $LogFilePath = (Split-Path -Parent -Path $MyInvocation.MyCommand.Definition),
[String] $LogFileBaseName = "_CreateHash-Job.log",
[String] $LogFileDateTime = "yyyyMMdd.HHmmss",
[bool] $CreateHashForEachFile = $true,
[bool] $CreateHashForAllFiles = $true,
[bool] $NoLogging = $true,
[bool] $DebugLogging = $false,
[bool] $DebugToScreen = $false,
[bool] $RemoveExistingHashFiles = $true
)
##------------------------------------------------------------------------------------------------
## Initialization
##------------------------------------------------------------------------------------------------
begin {
#------------------------------------------------------------------------------------------------
# Configure Environment and basic functions
#------------------------------------------------------------------------------------------------
# LOGWRITER
$Date = Get-Date -Format $LogFileDateTime
function Write-Log ($Entry, $DebugEntry) {
if (-not $NoLogging) {
$DateTime = Get-Date -Format "yyyyMMdd;HHmmss;"
$FileName = Join-Path -Path $LogFilePath -ChildPath ($Date + $LogFileBaseName)
if ($DebugToScreen) {
if ($Entry) {
Write-Host -ForegroundColor Cyan ($DateTime+$Entry)
}
if ($DebugEntry) {
Write-Host -ForegroundColor Magenta ($DateTime+"[DEBUG]") -nonewline
Write-Host -ForegroundColor Cyan $DebugEntry
}
}
if ($LogFilePath.Length -eq 0) {
$FileName = ($Date + "-" + $LogFileBaseName)
}
if ($Entry) {
Add-Content -Path $FileName -Value ($DateTime + $Entry)
}
if ($DebugLogging -and $DebugEntry) {
Add-Content -Path $FileName -Value ($DateTime +" [DEBUG] "+ $DebugEntry)
}
}
}
# FILEHASH GENERATOR
function Create-FileHash ($FileName, $HashAlgorithm) {
try {
$file = [System.IO.File]::Open($FileName,[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
$HASH = (([System.BitConverter]::ToString($CProvider.ComputeHash($file))).Replace("-", "")).ToLower()
$file.Dispose()
return ($HASH)
}
catch {
Write-Log -Entry "[ERROR] creating hash for file: $FileName"
return ("[ERROR]")
}
}
### USER INTERFACE
Write-Log -Entry "Beginning hash file creation..." -DebugEntry (Get-Date)
Write-Host -ForegroundColor Green "Beginning hash file creation..."
Write-Host -ForegroundColor Yellow "LogFilePath: " -NoNewline
Write-Host $LogFilePath
Write-Host -ForegroundColor Yellow "Input path: " -NoNewline
Write-Host $InputPath
# CHECK: InputPath clean up
if ($InputPath[($InputPath.Length)-1] -ne "\") {
$InputPath = $InputPath+"\"
}
$InputPath = $InputPath.ToLower()
#------------------------------------------------------------------------------------------------
# CHECK: Input path...
if (-not (Test-Path -Path $InputPath)) {
Write-Log -Entry "[Error] Input Path not accessible"
Write-Error "[ERROR] Input Path not accessible"
exit
}
#------------------------------------------------------------------------------------------------
# CHECK: Hashing ‎algorithm
try {
$HashAlgorithm = ([string]$HashAlgorithm).ToLower()
Write-Log -DebugEntry ("Testing hashing algorithm successful")
}
catch {
Write-Error -Exception "Invalid Input Type" -Message "The entered hash algorithm is provided in the wrong format [STRING] is required!"
}
switch ($HashAlgorithm) {
"md5" {
$ExpectedHashSize = 128
$HashfileEnding = "md5"
$CProvider = new-object System.Security.Cryptography.MD5CryptoServiceProvider
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding applied!")
break
}
"sha1" {
$ExpectedHashSize = 160
$HashfileEnding = "sha"
$CProvider = new-object System.Security.Cryptography.SHA1CryptoServiceProvider
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding applied!")
break
}
"sha256" {
$ExpectedHashSize = 256
$HashfileEnding = "sha256"
try {
$CProvider = new-object System.Security.Cryptography.SHA256CryptoServiceProvider
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding applied!")
}
catch {
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding failed!")
Write-Error -Message "SHA256 seems not to work on this system..."
}
break
}
"sha512" {
$ExpectedHashSize = 512
$HashfileEnding = "sha512"
try {
$CProvider = new-object System.Security.Cryptography.SHA512CryptoServiceProvider
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding applied!")
}
catch {
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding failed!")
Write-Error -Message "SHA256 seems not to work on this system..."
}
break
}
default {
$HashfileEnding = "sha"
$CProvider = new-object System.Security.Cryptography.SHA1CryptoServiceProvider
Write-Log -DebugEntry ("Settings for algorithm: $HashfileEnding applied!")
}
}
# Fail back ‎algorithm
if ($CProvider.HashSize -ne $ExpectedHashSize) {
$CProvider = new-object System.Security.Cryptography.SHA1CryptoServiceProvider
Write-Warning -Message "Failing back to SHA1 hash algorithm..."
Write-Log -DebugEntry ("Failing back to SHA1 hash algorithm")
}
Write-Log -Entry ("Hash algorithm used: $HashfileEnding")
### USER INTERFACE
Write-Host -ForegroundColor Green "Hash algorithm used: " -NoNewline
Write-Host $HashfileEnding
}
##------------------------------------------------------------------------------------------------
## Main block
##------------------------------------------------------------------------------------------------
process {
#------------------------------------------------------------------------------------------------
# Retrieve files in InputDirectory
#------------------------------------------------------------------------------------------------
$AllFilesName = "AllFilesHash"
$FileList = @()
# When removing existing hash files (default)
if ($RemoveExistingHashFiles) {
$FileList = Get-ChildItem -Path $InputPath -Filter $InputFileMask -Recurse | Where-Object {$_.PSIsContainer -eq $false -and $_.Extension -ne ("."+$HashfileEnding)} | Select-Object FullName, CreationTime, FileHash
}
# When keeping existing hash files
else {
$FileList = Get-ChildItem -Path $InputPath -Filter $InputFileMask -Recurse | Where-Object {$_.PSIsContainer -eq $false} | Select-Object FullName, CreationTime, FileHash
}
#------------------------------------------------------------------------------------------------
# Verify there is something to do...
#------------------------------------------------------------------------------------------------
$FileCount = $FileList | Measure-Object | Select-Object -ExpandProperty Count
if ($FileCount -eq 0) {
Write-Warning "No file to create hashes..."
Write-Log -Entry "[INFO] No file to create hasehs..." -DebugEntry "in source"
exit
}
##------------------------------------------------------------------------------------------------
## Create hashes for selected files and create hash files
##------------------------------------------------------------------------------------------------
if ($CreateHashForAllFiles -or $CreateHashForEachFile) {
#------------------------------------------------------------------------------------------------
# Create hashes
$Progress = 1
$FileList | foreach {
Write-Progress -Activity "Creating file hashes" -CurrentOperation ("Processing file $Progress of $FileCount ("+$_.FullName+")") -PercentComplete ($Progress / $FileCount * 100) -Status "working"
$Progress++
Write-Log -DebugEntry ("Creating hash for: "+$_.FullName)
$_.FileHash = Create-FileHash -Filename $_.FullName -HashAlgorithm $HashAlgorithm
$_.FullName = ($_.FullName.ToLower()).Replace($InputPath, "")
Write-Log -DebugEntry ("Hash for: "+$_.FullName+" "+$_.FileHash)
}
Write-Progress -Activity "Creating file hashes" -Completed -Status "complete"
#------------------------------------------------------------------------------------------------
# Create combined file with all hashes
if ($CreateHashForAllFiles) {
if ((Split-Path -Path $InputPath -Leaf) -ne $InputPath) {
$AllFilesName = Split-Path -Path $InputPath -Leaf
}
$HashFileName = ($InputPath+$AllFilesName+"."+$HashfileEnding)
Write-Log -Entry "Creating one hash file for all files" -DebugEntry ("FileName: "+ $HashFileName)
if (Test-Path -Path $HashFileName) {
Write-Log -Entry "Removing existing hash file!"
$null = Remove-Item -Path $HashFileName -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
}
try {
$Progress = 1
$FileList | foreach {
Write-Progress -Activity "Writing hashes to overall hash file" -CurrentOperation ("Processing hash: $Progress of $FileCount ("+$_.FullName+")") -PercentComplete ($Progress / $FileCount * 100) -Status "working"
$Progress++
Write-Log -DebugEntry ($_.FullName+" "+$_.FileHash)
Add-Content -Path $HashFileName -Value ($_.FileHash+" "+$_.FullName) -Encoding UTF8
}
}
catch {}
}
#------------------------------------------------------------------------------------------------
#Create individual hash file
if ($CreateHashForEachFile) {
Write-Log -Entry "Creating individual hash files..."
try {
$Progress = 1
$FileList | foreach {
Write-Progress -Activity "Writing hashes to hash files" -CurrentOperation ("Processing hash file: $Progress of $FileCount ("+$_.FullName+"."+$HashfileEnding+")") -PercentComplete ($Progress / $FileCount * 100) -Status "working"
$Progress++
$HashFileName = ($InputPath+$_.FullName+"."+$HashfileEnding)
Write-Log -DebugEntry ($HashFileName+" "+$_.FileHash)
if ($RemoveExistingHashFiles -and (Test-Path -Path $HashFileName)) {
Write-Log -Entry "Removing existing hash file: $HashFileName"
$null = Remove-Item -Path $HashFileName -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
}
Add-Content -Path $HashFileName -Value ($_.FileHash+" "+(Split-Path -Path $_.FullName -Leaf)) -Encoding UTF8
}
}
catch {}
}
}
Write-Progress -Activity "Writing hashes to hash files" -Completed -Status "complete"
#------------------------------------------------------------------------------------------------
# Finished
Write-Log -Entry "Operation finished! Script will end now." -DebugEntry (Get-Date)
}
Download the script:
>> Version 1.0.1 (current)
(MD5: dd92690aacb047739659e844faf523c3)
(SHA1: 724aaddafa8796cf06af9d7c643a9dd294d63dbf)