There are a lot of questions and answers about comparing the hash of two folder for integrity like this one. Assuming I have a folder that I copied to a backup medium (External drive, flash, optical disc) and would like to delete the original to save space.
What is the best way to save the original's folder hashes (before deletion) in a text file perhaps and check the backup's integrity much later against that file.
CodePudding user response:
Note that if you delete the originals first and later find that the backup lacks integrity, so to speak, all you'll know is that something went wrong; the non-corrupted data will be gone.
You can create a CSV file with 2 columns, RelativePath
(the full file path relative to the input directory) and Hash
, and save it to a CSV file with Export-Csv
:
$inputDir = 'C:\path\to\dir' # Note: specify a *full* path.
$prefixLen = $inputDir.Length 1
Get-ChildItem -File -Recurse -LiteralPath $inputDir |
Get-FileHash |
Select-Object @{
Name='RelativePath'
Expression={ $_.Path.Substring($prefixLen) }
},
Hash |
Export-Csv originalHashes.csv -NoTypeInformation -Encoding utf8
Note: In PowerShell (Core) 7 , neither -NoTypeInformation
nor -Encoding utf8
are needed, though note that the file will have no UTF-8 BOM; use -Encoding utf8bom
if you want one; conversely, in Windows PowerShell you invariably get a BOM.
Note:
The
Microsoft.PowerShell.Commands.FileHashInfo
instances output byGet-FileHash
also have an.Algorithm
property naming the hashing algorithm that was used ('SHA256'
by default, or as specified via the-Algorithm
parameter).
If you want this property included (whose value will be the same for all CSV rows), you simply addAlgorithm
to the array of properties passed toSelect-Object
above.Note how a hashtable (
@{ ... }
) passed as the second property argument toSelect-Object
serves as a calculated property that derives the relative path from each.Path
property value (which contains the full path).
You can later apply the same command to the backup directory tree, saving to, say, backupHashes.csv
, and compare the two CSV files with Compare-Object
:
Compare-Object (Import-Csv -LiteralPath originalHashes.csv) `
(Import-Csv -LiteralPath backupHashes.csv) `
-Property RelativePath, Hash
Note: There's no strict need to involve files in the operation - one or both output collections can be captured in memory and can be used directly in the comparison - just omit the Export-Csv
call in the command above and save to a variable ($originalHashes = Get-ChildItem ...
)