Refactor Invoke-WPFFixesUpdate and replace Invoke-WPFPanelDISM with Invoke-WPFSystemRepair. Streamline Windows Repair

This commit is contained in:
Marterich 2025-04-08 20:56:59 +02:00
parent 698f1644c3
commit 642367509d
4 changed files with 168 additions and 142 deletions

View File

@ -34,7 +34,7 @@ function Invoke-WPFButton {
"WPFRemoveUltPerf" {Invoke-WPFUltimatePerformance -State "Disable"} "WPFRemoveUltPerf" {Invoke-WPFUltimatePerformance -State "Disable"}
"WPFundoall" {Invoke-WPFundoall} "WPFundoall" {Invoke-WPFundoall}
"WPFFeatureInstall" {Invoke-WPFFeatureInstall} "WPFFeatureInstall" {Invoke-WPFFeatureInstall}
"WPFPanelDISM" {Invoke-WPFPanelDISM} "WPFPanelDISM" {Invoke-WPFSystemRepair}
"WPFPanelAutologin" {Invoke-WPFPanelAutologin} "WPFPanelAutologin" {Invoke-WPFPanelAutologin}
"WPFPanelcontrol" {Invoke-WPFControlPanel -Panel $button} "WPFPanelcontrol" {Invoke-WPFControlPanel -Panel $button}
"WPFPanelnetwork" {Invoke-WPFControlPanel -Panel $button} "WPFPanelnetwork" {Invoke-WPFControlPanel -Panel $button}

View File

@ -6,19 +6,7 @@ function Invoke-WPFFixesUpdate {
Performs various tasks in an attempt to repair Windows Update Performs various tasks in an attempt to repair Windows Update
.DESCRIPTION .DESCRIPTION
1. (Aggressive Only) Scans the system for corruption using chkdsk, SFC, and DISM 1. (Aggressive Only) Scans the system for corruption using the Invoke-WPFSystemRepair function
Steps:
1. Runs chkdsk /scan /perf
/scan - Runs an online scan on the volume
/perf - Uses more system resources to complete a scan as fast as possible
2. Runs SFC /scannow
/scannow - Scans integrity of all protected system files and repairs files with problems when possible
3. Runs DISM /Online /Cleanup-Image /RestoreHealth
/Online - Targets the running operating system
/Cleanup-Image - Performs cleanup and recovery operations on the image
/RestoreHealth - Scans the image for component store corruption and attempts to repair the corruption using Windows Update
4. Runs SFC /scannow
Ran twice in case DISM repaired SFC
2. Stops Windows Update Services 2. Stops Windows Update Services
3. Remove the QMGR Data file, which stores BITS jobs 3. Remove the QMGR Data file, which stores BITS jobs
4. (Aggressive Only) Renames the DataStore and CatRoot2 folders 4. (Aggressive Only) Renames the DataStore and CatRoot2 folders
@ -46,104 +34,7 @@ function Invoke-WPFFixesUpdate {
Start-Sleep -Milliseconds 200 Start-Sleep -Milliseconds 200
if ($Aggressive) { if ($Aggressive) {
# Scan system for corruption Invoke-WPFSystemRepair
Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Scanning for corruption..." -PercentComplete 0
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running chkdsk..." -PercentComplete 0
# 2>&1 redirects stdout, alowing iteration over the output
chkdsk.exe /scan /perf 2>&1 | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Get the index of the total percentage
$index = $_.IndexOf("Total:")
if (
# If the percent is found
($percent = try {(
$_.Substring(
$index + 6,
$_.IndexOf("%", $index) - $index - 6
)
).Trim()} catch {0}) `
<# And the current percentage is greater than the previous one #>`
-and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running chkdsk... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC..." -PercentComplete 0
$oldpercent = 0
# SFC has a bug when redirected which causes it to output only when the stdout buffer is full, causing the progress bar to move in chunks
sfc /scannow 2>&1 | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if (
(
# Use a different method to get the percentage that accounts for SFC's Unicode output
[int]$percent = try {(
(
$_.Substring(
$_.IndexOf("n") + 2,
$_.IndexOf("%") - $_.IndexOf("n") - 2
).ToCharArray() | Where-Object {$_}
) -join ''
).TrimStart()} catch {0}
) -and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM..." -PercentComplete 0
$oldpercent = 0
DISM /Online /Cleanup-Image /RestoreHealth | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if (
($percent = try {
[int]($_ -replace "\[" -replace "=" -replace " " -replace "%" -replace "\]")
} catch {0}) `
-and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC again..." -PercentComplete 0
$oldpercent = 0
sfc /scannow 2>&1 | ForEach-Object {
# Write stdout to the Verbose stream
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if (
(
[int]$percent = try {(
(
$_.Substring(
$_.IndexOf("n") + 2,
$_.IndexOf("%") - $_.IndexOf("n") - 2
).ToCharArray() | Where-Object {$_}
) -join ''
).TrimStart()} catch {0}
) -and $percent -gt $oldpercent
) {
# Update the progress bar
$oldpercent = $percent
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC... ($percent%)" -PercentComplete $percent
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Completed" -PercentComplete 100
} }

View File

@ -1,30 +0,0 @@
function Invoke-WPFPanelDISM {
<#
.SYNOPSIS
Checks for system corruption using Chkdsk, SFC, and DISM
.DESCRIPTION
1. Chkdsk - Fixes disk and filesystem corruption
2. SFC Run 1 - Fixes system file corruption, and fixes DISM if it was corrupted
3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
4. SFC Run 2 - Fixes system file corruption, this time with an almost guaranteed uncorrupted system image
.NOTES
Command Arguments:
1. Chkdsk
/Scan - Runs an online scan on the system drive, attempts to fix any corruption, and queues other corruption for fixing on reboot
2. SFC
/ScanNow - Performs a scan of the system files and fixes any corruption
3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
/Online - Fixes the currently running system image
/Cleanup-Image - Performs cleanup operations on the image, could remove some unneeded temporary files
/Restorehealth - Performs a scan of the image and fixes any corruption
#>
Start-Process PowerShell -ArgumentList "Write-Host '(1/4) Chkdsk' -ForegroundColor Green; Chkdsk /scan;
Write-Host '`n(2/4) SFC - 1st scan' -ForegroundColor Green; sfc /scannow;
Write-Host '`n(3/4) DISM' -ForegroundColor Green; DISM /Online /Cleanup-Image /Restorehealth;
Write-Host '`n(4/4) SFC - 2nd scan' -ForegroundColor Green; sfc /scannow;
Read-Host '`nPress Enter to Continue'" -verb runas
}

View File

@ -0,0 +1,165 @@
function Invoke-WPFSystemRepair {
<#
.SYNOPSIS
Checks for system corruption using Chkdsk, SFC, and DISM
.DESCRIPTION
1. Chkdsk - Fixes disk and filesystem corruption
2. SFC Run 1 - Fixes system file corruption, and fixes DISM if it was corrupted
3. DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
4. SFC Run 2 - Fixes system file corruption, this time with an almost guaranteed uncorrupted system image
#>
Write-Progress -Id 0 -Activity "Repairing Windows" -PercentComplete 0
# Wait for the first progress bar to show, otherwise the second one won't show
Start-Sleep -Milliseconds 200
function run_chkdsk {
<#
.SYNOPSIS
Runs chkdsk on the system drive
.DESCRIPTION
Chkdsk /Scan - Runs an online scan on the system drive, attempts to fix any corruption, and queues other corruption for fixing on reboot
.PARAMETER verbose
If specified, print output from chkdsk
.NOTES
VerbosePreference is defined locally, so it only affects this function. This is done by wrapping the code inside a script block and calling it with & { ... }
#>
param(
[switch]$verbose
)
& {
if ($verbose) {
$VerbosePreference = "Continue"
}
else {
$VerbosePreference = "SilentlyContinue"
}
Write-Progress -Id 1 -Activity "Scanning for corruption" -Status "Running chkdsk..." -PercentComplete 0
$oldpercent = 0
# 2>&1 redirects stdout, allowing iteration over the output
chkdsk.exe /scan /perf 2>&1 | ForEach-Object {
Write-Verbose $_
# Regex to match the total percentage regardless of windows locale (it's always the second percentage in the status output)
if ($_ -match "%.*?(\d+)%") {
[int]$percent = $matches[1]
if ($percent -gt $oldpercent) {
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running chkdsk... ($percent%)" -PercentComplete $percent
$oldpercent = $percent
}
}
}
Write-Progress -Id 1 -Activity "Scanning for corruption" -Status "chkdsk Completed" -PercentComplete 100
}
}
function run_sfc {
<#
.SYNOPSIS
Runs sfc on the system drive
.DESCRIPTION
SFC /ScanNow - Performs a scan of the system files and fixes any corruption
.PARAMETER verbose
If specified, print output from sfc
.NOTES
VerbosePreference and ErrorPreference is defined locally, so it only affects this function. This is done by wrapping the code inside a script block and calling it with & { ... }
#>
param(
[switch]$verbose
)
& {
if ($verbose) {
$VerbosePreference = "Continue"
}
else {
$VerbosePreference = "SilentlyContinue"
}
$ErrorActionPreference = "SilentlyContinue"
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC..." -PercentComplete 0
$oldpercent = 0
# SFC has a bug when redirected which causes it to output only when the stdout buffer is full, causing the progress bar to move in chunks
sfc.exe /scannow 2>&1 | ForEach-Object {
Write-Verbose $_
if ($_ -ne "") {
# sfc.exe /scannow outputs unicode characters, so we directly remove null characters for optimization
$utf8line = $_ -replace "`0", ""
if ($utf8line -match "(\d+)\s%") {
# Write-Host "$($matches[0]) $($matches[1])"
[int]$percent = $matches[1]
if ($percent -gt $oldpercent) {
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC... ($percent%)" -PercentComplete $percent
$oldpercent = $percent
}
}
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "SFC Completed" -PercentComplete 100
}
}
function run_dism {
<#
.SYNOPSIS
Runs DISM on the system drive
.DESCRIPTION
DISM - Fixes system image corruption, and fixes SFC's system image if it was corrupted
/Online - Fixes the currently running system image
/Cleanup-Image - Performs cleanup operations on the image, could remove some unneeded temporary files
/Restorehealth - Performs a scan of the image and fixes any corruption
.PARAMETER verbose
If specified, print output from DISM
.NOTES
VerbosePreference is defined locally, so it only affects this function. This is done by wrapping the code inside a script block and calling it with & { ... }
#>
param(
[switch]$verbose
)
& {
if ($verbose) {
$VerbosePreference = "Continue"
}
else {
$VerbosePreference = "SilentlyContinue"
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM..." -PercentComplete 0
$oldpercent = 0
DISM /Online /Cleanup-Image /RestoreHealth | ForEach-Object {
Write-Verbose $_
# Filter for lines that contain a percentage that is greater than the previous one
if ($_ -match "(\d+)[.,]\d+%") {
[int]$percent = $matches[1]
if ($percent -gt $oldpercent) {
# Update the progress bar
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM... ($percent%)" -PercentComplete $percent
$oldpercent = $percent
}
}
}
Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "DISM Completed" -PercentComplete 100
}
}
# Scan system for corruption
Write-Progress -Id 0 -Activity "Repairing Windows" -Status "Scanning for corruption... " -PercentComplete 0
# Step 1: Run chkdsk to fix disk and filesystem corruption before proceeding with system file repairs
run_chkdsk
Write-Progress -Id 0 -Activity "Repairing Windows" -Status "Scanning for corruption... (25%)" -PercentComplete 25
# Step 2: Run SFC to fix system file corruption and ensure DISM can operate correctly
run_sfc
Write-Progress -Id 0 -Activity "Repairing Windows" -Status "Scanning for corruption... (50%)" -PercentComplete 50
# Step 3: Run DISM to repair the system image, which SFC relies on for accurate repairs
run_dism
Write-Progress -Id 0 -Activity "Repairing Windows" -Status "Scanning for corruption... (75%)" -PercentComplete 75
# Step 4: Run SFC again to ensure system files are repaired using the now-fixed system image
run_sfc
Write-Progress -Id 0 -Activity "Repairing Windows" -Status "Scanning for corruption completed" -PercentComplete 100
}