When I am investigating or troubleshooting any issue, I always hope to have access to any log, source control, build artifacts, and pipelines. However, some scenarios are not related to software development where the only resources that I have immediate access to are folders and the files contained, and also the same ones but from a daily backup.
What happened to me at least twice was the need of at glance of compare files and folders by using hashes and relative file paths to identify missing or new files.
Both times I wrote something on the spot, it was rough but it did the job. It gave me the answer that I was looking for and I knew that the folders and their content were exactly the same.
This last time when I was asked if I had something ready for this I thought that writing an article to share it could be beneficial for the whole community.
Outcomes
Given 2 distinct folders I wanted to analyse the relative path and the hash of each of the files to identify if the content was identical or not. If the latter knowing if the file was added, missing or changed is also equally important.
Compare-Folder PowerShell script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
#Paolo Frigo, https://scriptinglibrary.com <# .SYNOPSIS Compare the contents of two folders based on file hashes. .DESCRIPTION This script calculates SHA256 hashes for all files in two specified folders (and their subdirectories) and compares them. It outputs any differences in file content or structure. .PARAMETER Folder1 The absolute path to the first folder to compare. .PARAMETER Folder2 The absolute path to the second folder to compare. .EXAMPLE Compare-Folders.ps1 -Folder1 "C:\Path\To\Folder1" -Folder2 "C:\Path\To\Folder2" This compares the contents of "Folder1" and "Folder2" and outputs any differences. .NOTES Author: Paolo Frigo #> param ( [Parameter(Mandatory)] [string]$Folder1, [Parameter(Mandatory)] [string]$Folder2 ) function Get-RelativePath { param ( [string]$FullPath, [string]$BasePath ) return $FullPath.Substring($BasePath.Length).TrimStart('\') } $folder1Hashes = Get-ChildItem -Path $Folder1 -File -Recurse | ForEach-Object { [PSCustomObject]@{ RelativePath = $_.FullName.Substring((Resolve-Path $Folder1).Path.Length + 1) Hash = (Get-FileHash $_.FullName).Hash } } $folder2Hashes = Get-ChildItem -Path $Folder2 -File -Recurse | ForEach-Object { [PSCustomObject]@{ RelativePath = $_.FullName.Substring((Resolve-Path $Folder2).Path.Length + 1) Hash = (Get-FileHash $_.FullName).Hash } } $differences = Compare-Object -ReferenceObject $folder1Hashes -DifferenceObject $folder2Hashes -Property RelativePath, Hash -PassThru if ($differences) { Write-Host "Differences found:" $differences | Format-Table -Property RelativePath, Hash, SideIndicator Write-Host "`nExplanation of SideIndicator:" Write-Host "'<= ' means the file exists only in Folder1." Write-Host "'=> ' means the file exists only in Folder2." Write-Host "' ' means the file exists in both folders but has different content." } else { Write-Host "The folders are identical (both file content and structure)." } |
Conclusions
When you need to test your assumptions simple tools may help you to gather some clues or preliminary information that help you move quickly to find the root cause.
This script is very basic, but the outcome of comparing the content of two folders recursively is more powerful than it seems.
I hope you will find it useful! As usual, you can find this script on my Github repository.