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}