Compare a trusted baseline
Separate changed, missing, and unexpected files when comparing an evidence folder with a baseline.
Comparison has two directions
A baseline lists what was present earlier. Start by checking each baseline entry against the current files. If the name is missing, report Missing. If the name exists but its SHA-256 differs, report Changed. An unchanged file needs no finding for this task.
Then check the other direction: current files that have no baseline entry are Unexpected. Looking only through the baseline misses additions. Looking only through current files misses deletions.
Keep the comparison understandable
This lab has a flat directory with unique filenames, so Name is the comparison key. A recursive inventory should use a normalised relative path instead; two subdirectories can contain the same basename. State the key in your report contract.
Get-Content '/home/user/baseline.json' -Raw | ConvertFrom-Json
Use literal paths when hashing the current files. Do not “repair” the folder or update the baseline: this is a read-only comparison. A difference is an observation, not an instruction to delete a file.
The supplied baseline is trusted for this exercise. Outside the lab, you must establish when it was captured, who controlled it, and whether it was protected against modification. A changed hash can reflect a legitimate update. Your result should describe the difference precisely and leave intent to further investigation.
Get-Content '/home/user/baseline.json' -Raw | ConvertFrom-Json | Select-Object Name, SHA256
Put it into practice.
Compare /home/user/evidence with baseline.json by filename. Emit Name and Status for differences only: Changed, Missing, or Unexpected. Hash current files with SHA-256 and leave inputs and baseline untouched. This is a flat directory; unchanged files must not produce findings.
See an explained solution
$baseline = @(Get-Content '/home/user/baseline.json' -Raw | ConvertFrom-Json)
$current = @(Get-ChildItem '/home/user/evidence' -File)
foreach ($entry in $baseline) {
$file = $current | Where-Object Name -EQ $entry.Name
if (-not $file) { [pscustomobject]@{ Name=$entry.Name; Status='Missing' } }
elseif ((Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash -ne $entry.SHA256) {
[pscustomobject]@{ Name=$entry.Name; Status='Changed' }
}
}
foreach ($file in $current) {
if ($file.Name -notin $baseline.Name) { [pscustomobject]@{ Name=$file.Name; Status='Unexpected' } }
}
The first pass detects removals and byte changes; the second detects additions. No result is emitted for notes.txt because its hash still matches.