How to Find Duplicate Files with PowerShell and Export a Report
PowerShell can narrow a duplicate-file audit by grouping files with the same size and then calculating SHA-256 hashes only for those candidates. The script below exports matching-content groups and a separate scan-error report. It never deletes or moves a file.
Set the scan folder and report paths
$RootPath = "$env:USERPROFILE\Documents"
$ReportPath = "$env:USERPROFILE\Desktop\Duplicate_Audit_Report.csv"
$ErrorPath = "$env:USERPROFILE\Desktop\Duplicate_Scan_Errors.csv"
Use size grouping before hashing
$ScanErrors = @()
$allFiles = Get-ChildItem -LiteralPath $RootPath -File -Recurse -Force `
-ErrorAction SilentlyContinue -ErrorVariable +ScanErrors
$sizeCandidates = $allFiles |
Group-Object -Property Length |
Where-Object { $_.Count -gt 1 } |
ForEach-Object { $_.Group }
$hashedFiles = foreach ($file in $sizeCandidates) {
try {
$hash = Get-FileHash -LiteralPath $file.FullName `
-Algorithm SHA256 -ErrorAction Stop
[PSCustomObject]@{
Hash = $hash.Hash
Path = $file.FullName
SizeBytes = $file.Length
LastWriteTime = $file.LastWriteTime
}
}
catch {
$ScanErrors += [PSCustomObject]@{
Path = $file.FullName
Stage = "Hash"
Error = $_.Exception.Message
}
}
}
$report = foreach ($group in (
$hashedFiles |
Group-Object -Property Hash |
Where-Object { $_.Count -gt 1 }
)) {
$ordered = $group.Group | Sort-Object -Property Path
for ($index = 0; $index -lt $ordered.Count; $index++) {
[PSCustomObject]@{
GroupHash = $group.Name
GroupCount = $ordered.Count
CandidateRank = $index + 1
Path = $ordered[$index].Path
SizeMB = [math]::Round($ordered[$index].SizeBytes / 1MB, 2)
LastWriteTime = $ordered[$index].LastWriteTime
ReviewNote = "Matching SHA-256 content; review purpose and path"
}
}
}
if ($report) {
$report | Export-Csv -Path $ReportPath -NoTypeInformation -Encoding UTF8
Write-Host "Duplicate candidate report: $ReportPath"
}
else {
Write-Host "No matching SHA-256 groups were found in the files that were scanned."
}
if ($ScanErrors) {
$ScanErrors | Export-Csv -Path $ErrorPath -NoTypeInformation -Encoding UTF8
Write-Warning "Some paths could not be scanned. Review: $ErrorPath"
}
Understand what the report proves
A matching SHA-256 hash is a strong indication that the scanned file contents are identical. It does not show which path is the authoritative copy, whether both copies are required, or whether an application depends on a particular location. Scan errors also mean the audit was incomplete.
Run the script
- Save it as
find-duplicates.ps1. - Set
$RootPathto a folder you own and understand. - Run it in PowerShell.
- Open both CSV files if they were created.
- Do not proceed to cleanup until scan errors and intentional backup locations are reviewed.
Review each duplicate group
- Open files from more than one path.
- Check project, shortcut, sync, and application dependencies.
- Identify intentional archive, backup, sidecar, or distribution copies.
- Do not treat CandidateRank 1 as “the original”; it is only sorted first.
- Use the Recycle Bin or a separate holding folder before permanent deletion.
Why automatic deletion is excluded
Identical content can be intentional. A project may require a local copy, an archive may preserve a release, or software may reference a fixed path. The decision requires context the hash cannot provide.
Reduce incomplete or misleading scans
- Close applications that lock active files.
- Avoid scanning system and package directories without a specific reason.
- Exclude known backup trees if you are auditing only working folders.
- Keep the error CSV with the duplicate report.
- Repeat the scan after moving candidates to confirm no unexpected group remains.
Completion checklist
- The root path was intentional.
- Any scan or hash errors were reviewed.
- Each planned deletion has another verified copy.
- Dependent projects and applications were checked.
- Files were held temporarily before permanent removal.
- A post-cleanup scan and backup verification were completed.
Official Microsoft reference
Related Guides
- How to Create a Safer One-Way Backup with Robocopy — Back up important files before deleting suspected duplicates.
- How to Safely Bulk Rename Files with Python — Rename reviewed files in a predictable sequence while preserving extensions.
About the author
Tweaknook Editorial publishes practical guides and browser-based tools for everyday digital work. Product-dependent facts are checked against current primary documentation, with limitations and safer verification steps stated where relevant.