System Corruption Scan

functions/public/Invoke-WPFSystemRepair.ps1
  1function Invoke-WPFSystemRepair {
  2    <#
  3    .SYNOPSIS
  4        Checks for system corruption using Chkdsk, SFC, and DISM
  5
  6    .DESCRIPTION
  7        1. Chkdsk    - Fixes disk and filesystem corruption
  8        2. SFC Run 1 - Fixes system file corruption, and fixes DISM if it was corrupted
  9        3. DISM      - Fixes system image corruption, and fixes SFC's system image if it was corrupted
 10        4. SFC Run 2 - Fixes system file corruption, this time with an almost guaranteed uncorrupted system image
 11    #>
 12
 13    function Invoke-Chkdsk {
 14        <#
 15        .SYNOPSIS
 16            Runs chkdsk on the system drive
 17        .DESCRIPTION
 18            Chkdsk /Scan - Runs an online scan on the system drive, attempts to fix any corruption, and queues other corruption for fixing on reboot
 19        #>
 20        param(
 21            [int]$parentProgressId = 0
 22        )
 23
 24        Write-Progress -Id 1 -ParentId $parentProgressId -Activity $childProgressBarActivity -Status "Running chkdsk..." -PercentComplete 0
 25        $oldpercent = 0
 26        # 2>&1 redirects stdout, allowing iteration over the output
 27        chkdsk.exe /scan /perf 2>&1 | ForEach-Object {
 28            Write-Debug $_
 29            # Regex to match the total percentage regardless of windows locale (it's always the second percentage in the status output)
 30            if ($_ -match "%.*?(\d+)%") {
 31                [int]$percent = $matches[1]
 32                if ($percent -gt $oldpercent) {
 33                    Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "Running chkdsk... ($percent%)" -PercentComplete $percent
 34                    $oldpercent = $percent
 35                }
 36            }
 37        }
 38        Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "chkdsk Completed" -PercentComplete 100 -Completed
 39    }
 40
 41    function Invoke-SFC {
 42        <#
 43        .SYNOPSIS
 44            Runs sfc on the system drive
 45        .DESCRIPTION
 46            SFC /ScanNow - Performs a scan of the system files and fixes any corruption
 47        .NOTES
 48            ErrorActionPreference is set locally within a script block & {...} to isolate their effects.
 49            ErrorActionPreference suppresses false errors caused by sfc.exe output redirection.
 50            A bug in SFC output buffering causes progress updates to appear in chunks when redirecting output
 51        #>
 52        param(
 53            [int]$parentProgressId = 0
 54        )
 55        & {
 56            $ErrorActionPreference = "SilentlyContinue"
 57            Write-Progress -Id 1 -ParentId $parentProgressId -Activity $childProgressBarActivity -Status "Running SFC..." -PercentComplete 0
 58            $oldpercent = 0
 59            sfc.exe /scannow 2>&1 | ForEach-Object {
 60                Write-Debug $_
 61                if ($_ -ne "") {
 62                    # sfc.exe /scannow outputs unicode characters, so we directly remove null characters for optimization
 63                    $utf8line = $_ -replace "`0", ""
 64                    if ($utf8line -match "(\d+)\s*%") {
 65                        [int]$percent = $matches[1]
 66                        if ($percent -gt $oldpercent) {
 67                            Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "Running SFC... ($percent%)" -PercentComplete $percent
 68                            $oldpercent = $percent
 69                        }
 70                    }
 71                }
 72            }
 73            Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "SFC Completed" -PercentComplete 100 -Completed
 74        }
 75    }
 76
 77    function Invoke-DISM {
 78        <#
 79        .SYNOPSIS
 80            Runs DISM on the system drive
 81        .DESCRIPTION
 82            DISM                - Fixes system image corruption, and fixes SFC's system image if it was corrupted
 83              /Online           - Fixes the currently running system image
 84              /Cleanup-Image    - Performs cleanup operations on the image, could remove some unneeded temporary files
 85              /Restorehealth    - Performs a scan of the image and fixes any corruption
 86        #>
 87        param(
 88            [int]$parentProgressId = 0
 89        )
 90        Write-Progress -Id 1 -ParentId $parentProgressId -Activity $childProgressBarActivity -Status "Running DISM..." -PercentComplete 0
 91        $oldpercent = 0
 92        DISM /Online /Cleanup-Image /RestoreHealth | ForEach-Object {
 93            Write-Debug $_
 94            # Filter for lines that contain a percentage that is greater than the previous one
 95            if ($_ -match "(\d+)[.,]\d+%") {
 96                [int]$percent = $matches[1]
 97                if ($percent -gt $oldpercent) {
 98                    # Update the progress bar
 99                    Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "Running DISM... ($percent%)" -PercentComplete $percent
100                    $oldpercent = $percent
101                }
102            }
103        }
104        Write-Progress -Id 1 -Activity $childProgressBarActivity -Status "DISM Completed" -PercentComplete 100 -Completed
105    }
106
107    try {
108        Set-WinUtilTaskbaritem -state "Indeterminate" -overlay "logo"
109
110        $childProgressBarActivity = "Scanning for corruption"
111        Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 0
112        # Step 1: Run chkdsk to fix disk and filesystem corruption before proceeding with system file repairs
113        Invoke-Chkdsk
114        Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 25
115
116        # Step 2: Run SFC to fix system file corruption and ensure DISM can operate correctly
117        Invoke-SFC
118        Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 50
119
120        # Step 3: Run DISM to repair the system image, which SFC relies on for accurate repairs
121        Invoke-DISM
122        Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 75
123
124        # Step 4: Run SFC again to ensure system files are repaired using the now-fixed system image
125        Invoke-SFC
126        Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 100 -Completed
127
128        Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"
129    } catch {
130        Write-Error "An error occurred while repairing the system: $_"
131        Set-WinUtilTaskbaritem -state "Error" -overlay "warning"
132    } finally {
133        Write-Host "==> Finished System Repair"
134        Set-WinUtilTaskbaritem -state "None" -overlay "checkmark"
135    }
136
137}