@@ -0,0 +1,108 @@
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
$current = Get-FileHash - Path $filename - Algorithm MD5 - ErrorAction SilentlyContinue
} else {
$filename = $file
$current = Get-FileHash - Path $file - 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
}
}