1

I often run chkdsk /f X:(X here stands for actual drive letters), to check and fix filesystem errors, but it doesn't report which files are corrupted.

I use PSCore7.1 on Windows 10 20H2 x64, I want to check which files are corrupted by comparing hash and timestamp of a file against recorded hash and timestamp of that path, if the hash has changed and timestamp hasn't changed, then the file is corrupted.

PowerShell has builtin functions to get hash code, but it isn't SHA-256, I can use

Get-ChildItem -Path $path -Force -File -Recurse

To get files, .Fullname to get full path of files and .LastWriteTime to get timestamp, but here I am talking about whole disks so I want it to be as fast as possible.

But I don't know how to get SHA-256, though it shouldn't be hard.

Then my idea is to create a [PSCustomObject] with three noteproperties: Fullname, LastWriteTime and SHA-256, I can do this, then export it directly to a database file (append), unfortunately currently I only managed to export to txt files, and it would be difficult to query txt files.

Finally if the database doesn't exist, create it and exit, else if it does exist, get content of the database, create a new one in console and look for corrupted files.

I can use [System.IO.File]::Exists() to check if file exists, Convertfrom-String to convert txt to pscustomobject array, though it's buggy, or loop through file by index using for loop, in each iteration get values by regex match then create a PSCustomObject and add to array using +=, though this might be slow.

The final step to find corrupted files would be:

for ($i=0;$i -lt $NewDB.count;$i++) {
    $Database | Where-Object{$_.Fullname -eq $NewDB[$i].Fullname -and $_.LastWriteTime -eq $NewDB[$i].LastWriteTime -and $_.SHA256 -ne $NewDB[$i].SHA256}
}

I am not dumb, I am just inexperienced, currently there are there things required by this script which I am unable to do:

1, Get all files of a drive as fast as possible

2, Get SHA-256 of files

3, Export and import data

Please help me complete the script! Any help would be appreciated, I would be very grateful, and the answer may also help many other people, I say thanks in advance.

Update: Now I am looking for ways to export data to csv format, do I just use Out-File *.csv? Will it format data automatically? How do I control the format? And how to convert csv directly into an array of PSCustomObject?

Edit: fixed the missing index in the where line. Re-Edit: completed the for loop and where-object process to make it actually working, just in case someone would doubt my abilities or someone else who sees this and don't know how to do it.

3
  • 1
    Don't reinvent the wheel.
    – gronostaj
    Commented Dec 15, 2020 at 15:10
  • @gronostaj Your help is appreciated, but that script is Python and this question is about PowerShell, yes I know there exist such softwares but I want to write one myself, plus I can already write a working script, just that script would have very poor performance... Commented Dec 15, 2020 at 15:30
  • 1
    as for the hash, Get-FileHash should always return SHA256 by default. about the speed of Get-ChildItem I wouldn't mind it that much because I wouldn't run this script during working hours anyway, but if you really need it look into .net methods like [System.IO.Directory]::EnumerateFiles(). Or use cmd from PowerShell and parse the output in PS. I also saw you can create a VB Object that could also fit your needs. for the SQL Part use SQL Queries like if exists ... insert into ... update etc. and run them via Invoke-SqlCmd
    – SimonS
    Commented Dec 15, 2020 at 16:50

1 Answer 1

3

Getting hashes of a file, even the SHA level is a common thing and can be done natively in PowerShell, no need for 3rdP software. Always look at the help file full details first.

As for this…

I often run chkdsk /f X:(X here stands for actual drive letters), to check and fix filesystem errors, but it doesn't report which files are corrupted.

… because that is not what that tool is for. It’s to as documented.

https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/chkdsk

As for this…

…I want to check which files are corrupted by comparing hash and timestamp of a file against recorded hash and timestamp of that path, if the hash has changed and timestamp hasn't changed, then the file is corrupted.

… your PowerShell version has nothing to do with this use case. File hash change does not necessarily mean corruption. It means the content in the file was changed. A corrupt file in normal cases is not accessible because it's damaged..

As for …

…PowerShell has built-in functions to get hash code, but it isn't SHA-256…

… not true, this defined in the help files.

As for…

Get-ChildItem -Path $path -Force -File -Recurse

… it does not matter, because performance is controlled by the number of files targets, drive size, drive performance, CPU performance, ram, other processes impacting operational state (AV, etc), etc. Btw, doing this hash check will slow it down even more.

This means you break this up into chunks, PowerShell jobs, PowerShell workflows, Parallel processing to get some better performance.

As for…

But I don't know how to get SHA-256…

… the DPAPI of windows filesystem defaults to SHA-256, unless the programmer, data owner defined it otherwise using the DPAPI.

Yet, if you absolutely want to see that, the built-in cmdlet, Get-FileHash allows you to do this. It’s defined in the help files.

# Get specifics for a module, cmdlet, or function
(Get-Command -Name Get-FileHash).Parameters
(Get-Command -Name Get-FileHash).Parameters.Keys
Get-help -Name Get-FileHash -Examples
# Results
<#
Get-FileHash $pshome\powershell.exe | Format-List
Get-FileHash C:\Users\Andris\Downloads\Contoso8_1_ENT.iso -Algorithm SHA384 | Format-List
#>
Get-help -Name Get-FileHash -Full
Get-help -Name Get-FileHash -Online



Get-ChildItem -Path D:\Temp | 
ForEach{Get-FileHash -Path $PSItem.FullName}
# Results
<#
Algorithm       Hash                   Path                                                                                                      
---------       ----                    ----                                                                                                      
SHA256          84F07167E6A9E3...      D:\Temp\(MSINFO32) command-line...                                                        
SHA256          A3CB4415D3FAAA...      D:\Temp\23694d1213305764-revisi... 
...
#>

See also:

Carbon Black Defense: How to get a SHA 256 hash of a file on Windows and Mac

Steps for Windows - Powershell Open Windows Powershell Enter the following command (replace <path/to/file> with the absolute path of the file or application you want to get the hash from):

As for...

Then my idea is to create a [PSCustomObject] with three noteproperties: Fullname, LastWriteTime and SHA-256,...

... This:

Get-ChildItem -Path D:\Temp | 
ForEach{
    [PSCustomObject] @{
        FileName      = $PSItem.FullName
        LastWriteTIme = $PSItem.LastWriteTime
        ShaVersion    = (Get-FileHash -Path $PSItem.FullName).Algorithm 
        Hash          = (Get-FileHash -Path $PSItem.FullName).Hash 
    }
}
# Results
<#
FileName                        LastWriteTIme      ShaVersion Hash                                             
--------                        -------------      ---------- ----                                             
D:\Temp\(MSINFO32) command...   06-Aug-16 18:25:22 SHA256     84F07167E6A9E3...
D:\Temp\23694d1213305764-r...   06-Feb-20 14:02:47 SHA256     A3CB4415D3FAAA...
D:\Temp\5 Free Software Yo...   29-Dec-19 21:50:56 SHA256     3427AD8DC44986...
#>

Update as per your comment 'how to export to and import from csv'

Get-ChildItem -Path D:\Temp | 
ForEach{
    [PSCustomObject] @{
        FileName      = $PSItem.FullName
        LastWriteTIme = $PSItem.LastWriteTime
        ShaVersion    = (Get-FileHash -Path $PSItem.FullName).Algorithm 
        Hash          = (Get-FileHash -Path $PSItem.FullName).Hash 
    } | Export-Csv -Path 'D:\Temp\FileMoniotReport.csv' -NoTypeInformation -Append
}
Import-Csv -Path 'D:\Temp\FileMoniotReport.csv'
4
  • Thanks a lot, but you didn't mention how to export to and import from csv. Commented Dec 16, 2020 at 0:51
  • Just do that in the loop. See my update
    – postanote
    Commented Dec 16, 2020 at 1:09
  • A corrupt file in normal cases isn't accessable... It's true, but I can still open corrupted .mp3, .mp4, .mkv etc files, they are damage tolerant, you can open them, but the quality will degrade. Same for archive files, sometimes you can open zip files etc without error, but when you unzip it, the error messages will pop up when it tries to extract corrupted files... Commented Dec 16, 2020 at 1:22
  • The corruption happens in the middle so the file can be read, not all corruptions happen in header or end... Commented Dec 16, 2020 at 1:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .