Skip to content

Instantly share code, notes, and snippets.

@TheRockStarDBA
Forked from potatoqualitee/Test-FileHash.ps1
Created February 22, 2022 21:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TheRockStarDBA/3e70af13afb00fc4ccd5886d68b9eeb7 to your computer and use it in GitHub Desktop.
Save TheRockStarDBA/3e70af13afb00fc4ccd5886d68b9eeb7 to your computer and use it in GitHub Desktop.
Simple file hash comparison tool written in PowerShell
function Test-FileHash {
<#
.Synopsis
This is a simple file hash comparison tool that writes to Windows Events when changes are detected
.Description
This is a simple file hash comparison tool that writes to Windows Events when changes are detected
.PARAMETER FilePath
The path to the file to hash and compare
.PARAMETER DictionaryFile
The path to the directionary file with previously calculated hashes
Defaults to the current directory + compare.xml
This file is created if it does not exist
.NOTES
Copyright: (c) 2022 by Chrissy LeMaire, licensed under MIT
License: MIT https://opensource.org/licenses/MIT
.Example
PS> Test-FileHash -FilePath C:\indexes\index.json -DictionaryFile D:\audit\allhashes.xml
Tests to see if the filehash of the file at C:\indexes\index.json has changed since the last time it was hashed.
.Example
PS> Get-ChildItem -Recurse -Path "C:\Program Files\Microsoft SQL Server" | Test-FileHash -DictionaryFile D:\audit\allhashes.xml
Tests to see if the filehash of the file at C:\indexes\index.json has changed since the last time it was hashed.
#>
[CmdletBinding()]
param (
[parameter(ValueFromPipeline, Mandatory)]
[Alias("FileName", "FullName")]
[psobject[]]$FilePath, # this allows directories, gci and strings to be passed in
[System.IO.FileInfo]$DictionaryFile = ".\compare.xml"
)
begin {
# Test for admin -- it's needed to create the event log source
$user = [Security.Principal.WindowsIdentity]::GetCurrent()
$isadmin = (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
if (-not $isadmin) {
throw "You must run this script as administrator"
}
if ((Test-Path -Path $DictionaryFile)) {
$compare = Import-CliXml -Path $DictionaryFile
} else {
$compare = $null
$baseline = $true
}
if (-not ([System.Diagnostics.EventLog]::SourceExists("FileHash Checker"))) {
$null = New-EventLog -LogName Application -Source "FileHash Checker"
}
$message = New-Object System.Collections.ArrayList
$output = New-Object System.Collections.Hashtable
}
process {
foreach ($file in $FilePath) {
if ($file.FullName) {
$filename = $file.FullName
} else {
$filename = $file
}
$current = Get-FileHash -Path $filename -Algorithm MD5 -ErrorAction SilentlyContinue
if (-not $baseline -and $current) {
$original = $compare[$filename]
if ($original -ne $current.Hash) {
$currenthash = $current.Hash
$oldhash = $original
if (-not $original) {
$currentmessage = "$filename is a new file with a hash of $currenthash"
} else {
$currentmessage = "$filename had a previous hash of $oldhash but now has a hash of $currenthash"
}
$null = $message.Add($currentmessage)
Write-Warning -Message $currentmessage
}
}
if ($current) {
$null = $output.Add($filename, $current.Hash)
$current
}
}
}
end {
if ($message) {
# Just make one entry with all of the filehash failures
$params = @{
LogName = "Application"
Source = "FileHash Checker"
EntryType = "Warning"
Category = 0
EventId = 1000
Message = ($message -join [Environment]::NewLine)
}
Write-EventLog @params
}
$null = $output | Export-CliXml -Path $DictionaryFile
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment