(+351) 21 24 10006  ·  info@bconcepts.pt
Carnaxide, Lisbon

How to create a file integrity report in PowerShell

João Barros 09 de October de 2026 4 min read

This tutorial shows how to create a file integrity report in PowerShell to check for changes in critical files. The solution generates and stores hashes (SHA256) of files, compares later versions and highlights files added, removed or modified — useful for audits, detecting unauthorized changes and verified backups.

Prerequisites

  • Windows with PowerShell 5.1 or PowerShell 7+
  • Read permissions for the folder to be checked
  • A report folder where to store the reference file (JSON or CSV)

Step 1: Concept and report structure

It is important to understand what we will record: for each file we store the relative path, the size, the last modification date and the SHA256 hash. The JSON format is easy to read and simple to compare. The reference file will be named file-integrity.json.

Step 2: Script to generate the initial report

This script creates the initial report with all files in the target folder. Run it from the parent folder or provide a full path to $RootPath.

$RootPath = 'C:\PastaASeguir'  # Alterar para a pasta a verificar
$ReportFile = 'C:\Relatorios\file-integrity.json'  # Onde guardar o relatório

Get-ChildItem -Path $RootPath -Recurse -File | ForEach-Object {
    $relative = $_.FullName.Substring($RootPath.Length).TrimStart('\')
    $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256
    [PSCustomObject]@{
        Path = $relative
        Size = $_.Length
        LastWriteTime = $_.LastWriteTimeUtc
        Hash = $hash.Hash
    }
} | ConvertTo-Json -Depth 4 | Out-File -FilePath $ReportFile -Encoding UTF8

Write-Output "Relatório inicial gerado em: $ReportFile"

Step 3: Script to compare the current state with the report

This script loads the previous report, inspects the current state of the folder and identifies files Added, Removed and Modified. It also saves a new report with a timestamp for history.

$RootPath = 'C:\PastaASeguir'
$ReportFile = 'C:\Relatorios\file-integrity.json'
$NowReport = "C:\Relatorios\file-integrity-$(Get-Date -Format 'yyyyMMdd-HHmmss').json"

# Carregar relatório anterior
if (-Not (Test-Path $ReportFile)) { throw "Relatório anterior não encontrado: $ReportFile" }
$old = Get-Content $ReportFile -Raw | ConvertFrom-Json
$oldIndex = @{ }
foreach ($item in $old) { $oldIndex[$item.Path] = $item }

# Criar relatório atual em memória
$current = @()
Get-ChildItem -Path $RootPath -Recurse -File | ForEach-Object {
    $relative = $_.FullName.Substring($RootPath.Length).TrimStart('\')
    $hash = Get-FileHash -Path $_.FullName -Algorithm SHA256
    $current += [PSCustomObject]@{
        Path = $relative
        Size = $_.Length
        LastWriteTime = $_.LastWriteTimeUtc
        Hash = $hash.Hash
    }
}

# Index current
$currentIndex = @{ }
foreach ($item in $current) { $currentIndex[$item.Path] = $item }

# Detetar Added, Removed, Modified
$added = @()
$removed = @()
$modified = @()

foreach ($path in $currentIndex.Keys) {
    if (-Not $oldIndex.ContainsKey($path)) { $added += $currentIndex[$path] }
    else {
        $oldItem = $oldIndex[$path]
        $curItem = $currentIndex[$path]
        if ($oldItem.Hash -ne $curItem.Hash -or $oldItem.Size -ne $curItem.Size) {
            $modified += [PSCustomObject]@{
                Path = $path
                OldHash = $oldItem.Hash
                NewHash = $curItem.Hash
                OldSize = $oldItem.Size
                NewSize = $curItem.Size
            }
        }
    }
}

foreach ($path in $oldIndex.Keys) {
    if (-Not $currentIndex.ContainsKey($path)) { $removed += $oldIndex[$path] }
}

# Guardar relatório atual para histórico
$current | ConvertTo-Json -Depth 4 | Out-File -FilePath $NowReport -Encoding UTF8

# Output resumido
$summary = [PSCustomObject]@{
    Timestamp = (Get-Date).ToString('o')
    Added = $added.Count
    Removed = $removed.Count
    Modified = $modified.Count
    NewReport = $NowReport
}

$summary | ConvertTo-Json -Depth 3

# Também podemos guardar um log simples
$logFile = 'C:\Relatorios\file-integrity-log.txt'
Add-Content -Path $logFile -Value ("$((Get-Date).ToString('s')) - Added:$($added.Count) Removed:$($removed.Count) Modified:$($modified.Count)")

# Opcional: sobrescrever o relatório de referência para próxima comparação
$current | ConvertTo-Json -Depth 4 | Out-File -FilePath $ReportFile -Encoding UTF8

Step 4: Schedule or automate the check

To run automatically, use Task Scheduler. Create a task that runs PowerShell with the script path and parameters if needed. Configure it to run with appropriate permissions and with a trigger (e.g.: daily or hourly).

Verify the result

Check the JSON files and the log: the summary in JSON shows Added, Removed and Modified. Open the file file-integrity-log.txt for a quick history. In case of Modified, compare OldHash vs NewHash to confirm changes. Common errors: paths with insufficient permissions or exceptions on locked files — fix permissions or run with an account that has access.

Conclusion

You now have a simple solution to generate and compare file integrity reports with PowerShell; next steps include email notification when changes occur, excluding specific file types or integrating with SIEM. Tip: test first in a small folder to validate hashes and permissions before applying in production.