diff --git a/functions/public/Invoke-WPFFixesUpdate.ps1 b/functions/public/Invoke-WPFFixesUpdate.ps1 index 84bbaafe0a..27bd740626 100644 --- a/functions/public/Invoke-WPFFixesUpdate.ps1 +++ b/functions/public/Invoke-WPFFixesUpdate.ps1 @@ -7,6 +7,18 @@ function Invoke-WPFFixesUpdate { .DESCRIPTION 1. (Aggressive Only) Scans the system for corruption using chkdsk, SFC, and DISM + 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 3. Remove the QMGR Data file, which stores BITS jobs 4. (Aggressive Only) Renames the DataStore and CatRoot2 folders @@ -23,7 +35,7 @@ function Invoke-WPFFixesUpdate { 13. Forces Windows Update to check for updates .PARAMETER Aggressive - If specified, the script will take additional steps to repair Windows Update that are more dangerous or generally unnecessary + If specified, the script will take additional steps to repair Windows Update that are more dangerous, take a significant amount of time, or are generally unnecessary #> @@ -37,26 +49,114 @@ function Invoke-WPFFixesUpdate { # Scan system for corruption 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 - Start-Process -NoNewWindow -FilePath "chkdsk.exe" -ArgumentList "/scan", "/perf" - Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC..." -PercentComplete 25 - Start-Process -NoNewWindow -FilePath "sfc.exe" -ArgumentList "/scannow" - Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running DISM..." -PercentComplete 50 - Start-Process -NoNewWindow -FilePath "dism.exe" -ArgumentList "/online", "/cleanup-image", "/restorehealth" - Write-Progress -Id 1 -ParentId 0 -Activity "Scanning for corruption" -Status "Running SFC again..." -PercentComplete 75 - Start-Process -NoNewWindow -FilePath "sfc.exe" -ArgumentList "/scannow" + # 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 } + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Stopping Windows Update Services..." -PercentComplete 10 # Stop the Windows Update Services Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping BITS..." -PercentComplete 0 - Stop-Service -Name BITS + Stop-Service -Name BITS -Force Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping wuauserv..." -PercentComplete 20 - Stop-Service -Name wuauserv + Stop-Service -Name wuauserv -Force Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping appidsvc..." -PercentComplete 40 - Stop-Service -Name appidsvc + Stop-Service -Name appidsvc -Force Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping cryptsvc..." -PercentComplete 60 - Stop-Service -Name cryptsvc + Stop-Service -Name cryptsvc -Force Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Completed" -PercentComplete 100 @@ -96,6 +196,7 @@ function Invoke-WPFFixesUpdate { # Reregister the BITS and Windows Update DLLs Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Reregistering DLLs..." -PercentComplete 40 + $oldLocation = Get-Location Set-Location $env:systemroot\system32 $i = 0 $DLLs = @( @@ -112,6 +213,7 @@ function Invoke-WPFFixesUpdate { $i++ Start-Process -NoNewWindow -FilePath "regsvr32.exe" -ArgumentList "/s", $dll } + Set-Location $oldLocation Write-Progress -Id 5 -ParentId 0 -Activity "Reregistering DLLs" -Status "Completed" -PercentComplete 100 @@ -119,9 +221,9 @@ function Invoke-WPFFixesUpdate { if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate") { Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Removing WSUS client settings..." -PercentComplete 60 Write-Progress -Id 6 -ParentId 0 -Activity "Removing WSUS client settings" -PercentComplete 0 - Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "AccountDomainSid", "/f" - Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "PingID", "/f" - Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "SusClientId", "/f" + Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "AccountDomainSid", "/f" -RedirectStandardError $true + Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "PingID", "/f" -RedirectStandardError $true + Start-Process -NoNewWindow -FilePath "REG" -ArgumentList "DELETE", "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate", "/v", "SusClientId", "/f" -RedirectStandardError $true Write-Progress -Id 6 -ParentId 0 -Activity "Removing WSUS client settings" -Status "Completed" -PercentComplete 100 } @@ -129,9 +231,9 @@ function Invoke-WPFFixesUpdate { # Reset WinSock Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Resetting WinSock..." -PercentComplete 65 Write-Progress -Id 7 -ParentId 0 -Activity "Resetting WinSock" -Status "Resetting WinSock..." -PercentComplete 0 - Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winsock", "reset" - Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winhttp", "reset", "proxy" - Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "int", "ip", "reset" + Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winsock", "reset" -RedirectStandardOutput $true + Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "winhttp", "reset", "proxy" -RedirectStandardOutput $true + Start-Process -NoNewWindow -FilePath "netsh" -ArgumentList "int", "ip", "reset" -RedirectStandardOutput $true Write-Progress -Id 7 -ParentId 0 -Activity "Resetting WinSock" -Status "Completed" -PercentComplete 100 @@ -148,10 +250,12 @@ function Invoke-WPFFixesUpdate { Get-Service BITS | Set-Service -StartupType Manual -PassThru | Start-Service Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Starting wuauserv..." -PercentComplete 25 Get-Service wuauserv | Set-Service -StartupType Manual -PassThru | Start-Service - Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Starting appidsvc..." -PercentComplete 50 - Get-Service appidsvc | Set-Service -StartupType Manual -PassThru | Start-Service - Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Starting cryptsvc..." -PercentComplete 75 - Get-Service cryptsvc | Set-Service -StartupType Automatic -PassThru | Start-Service + Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Starting AppIDSvc..." -PercentComplete 50 + # The AppIDSvc service is protected, so the startup type has to be changed in the registry + Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\AppIDSvc" -Name "Start" -Value "3" # Manual + Start-Service AppIDSvc + Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Starting CryptSvc..." -PercentComplete 75 + Get-Service CryptSvc | Set-Service -StartupType Manual -PassThru | Start-Service Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Completed" -PercentComplete 100 @@ -173,6 +277,16 @@ function Invoke-WPFFixesUpdate { Write-Host "-- Reset All Windows Update Settings to Stock -" Write-Host "===============================================" - # Remove the progress bar + # Remove the progress bars Write-Progress -Id 0 -Activity "Repairing Windows Update" -Completed + Write-Progress -Id 1 -Activity "Scanning for corruption" -Completed + Write-Progress -Id 2 -Activity "Stopping Services" -Completed + Write-Progress -Id 3 -Activity "Renaming/Removing Files" -Completed + Write-Progress -Id 4 -Activity "Resetting the WU Service Security Descriptors" -Completed + Write-Progress -Id 5 -Activity "Reregistering DLLs" -Completed + Write-Progress -Id 6 -Activity "Removing WSUS client settings" -Completed + Write-Progress -Id 7 -Activity "Resetting WinSock" -Completed + Write-Progress -Id 8 -Activity "Deleting BITS jobs" -Completed + Write-Progress -Id 9 -Activity "Starting Windows Update Services" -Completed + Write-Progress -Id 10 -Activity "Forcing discovery" -Completed } \ No newline at end of file