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)


>> syntax highlighting powered by highlight.js