02 / FILE INTEGRITY AND EVIDENCE HANDLING · LESSON 06

Compare a trusted baseline

Separate changed, missing, and unexpected files when comparing an evidence folder with a baseline.

12 min · learn at your pace

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.

Try an example.ps1
Get-Content '/home/user/baseline.json' -Raw | ConvertFrom-Json | Select-Object Name, SHA256
YOUR TURN

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
One way to solve it.ps1
$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.