diff --git a/functions/public/Invoke-WPFFixesUpdate.ps1 b/functions/public/Invoke-WPFFixesUpdate.ps1 index 7e170b538e..27bd740626 100644 --- a/functions/public/Invoke-WPFFixesUpdate.ps1 +++ b/functions/public/Invoke-WPFFixesUpdate.ps1 @@ -5,77 +5,267 @@ function Invoke-WPFFixesUpdate { .SYNOPSIS Performs various tasks in an attempt to repair Windows Update + .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 + DataStore - Contains the Windows Update History and Log Files + CatRoot2 - Contains the Signatures for Windows Update Packages + 5. Renames the Windows Update Download Folder + 6. Deletes the Windows Update Log + 7. (Aggressive Only) Resets the Security Descriptors on the Windows Update Services + 8. Reregisters the BITS and Windows Update DLLs + 9. Removes the WSUS client settings + 10. Resets WinSock + 11. Gets and deletes all BITS jobs + 12. Sets the startup type of the Windows Update Services then starts them + 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, take a significant amount of time, or are generally unnecessary + #> - # Reset Windows Update Script - reregister dlls, services, and remove registry entries -Write-Host "1. Stopping Windows Update Services..." - Stop-Service -Name BITS - Stop-Service -Name wuauserv - Stop-Service -Name appidsvc - Stop-Service -Name cryptsvc -Write-Host "2. Remove QMGR Data file..." + param($Aggressive = $false) + + Write-Progress -Id 0 -Activity "Repairing Windows Update" -PercentComplete 0 + # Wait for the first progress bar to show, otherwise the second one won't show + Start-Sleep -Milliseconds 200 + + if ($Aggressive) { + # 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 + # 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 -Force + Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping wuauserv..." -PercentComplete 20 + Stop-Service -Name wuauserv -Force + Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping appidsvc..." -PercentComplete 40 + Stop-Service -Name appidsvc -Force + Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Stopping cryptsvc..." -PercentComplete 60 + Stop-Service -Name cryptsvc -Force + Write-Progress -Id 2 -ParentId 0 -Activity "Stopping Services" -Status "Completed" -PercentComplete 100 + + + # Remove the QMGR Data file + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Renaming/Removing Files..." -PercentComplete 20 + Write-Progress -Id 3 -ParentId 0 -Activity "Renaming/Removing Files" -Status "Removing QMGR Data files..." -PercentComplete 0 Remove-Item "$env:allusersprofile\Application Data\Microsoft\Network\Downloader\qmgr*.dat" -ErrorAction SilentlyContinue -Write-Host "3. Renaming the Software Distribution and CatRoot Folder..." - Rename-Item $env:systemroot\SoftwareDistribution SoftwareDistribution.bak -ErrorAction SilentlyContinue - Rename-Item $env:systemroot\System32\Catroot2 catroot2.bak -ErrorAction SilentlyContinue -Write-Host "4. Removing old Windows Update log..." + if ($Aggressive) { + # Rename the Windows Update Log and Signature Folders + Write-Progress -Id 3 -ParentId 0 -Activity "Renaming/Removing Files" -Status "Renaming the Windows Update Log, Download, and Signature Folder..." -PercentComplete 20 + Rename-Item $env:systemroot\SoftwareDistribution\DataStore DataStore.bak -ErrorAction SilentlyContinue + Rename-Item $env:systemroot\System32\Catroot2 catroot2.bak -ErrorAction SilentlyContinue + } + + # Rename the Windows Update Download Folder + Write-Progress -Id 3 -ParentId 0 -Activity "Renaming/Removing Files" -Status "Renaming the Windows Update Download Folder..." -PercentComplete 20 + Rename-Item $env:systemroot\SoftwareDistribution\Download Download.bak -ErrorAction SilentlyContinue + + # Delete the legacy Windows Update Log + Write-Progress -Id 3 -ParentId 0 -Activity "Renaming/Removing Files" -Status "Removing the old Windows Update log..." -PercentComplete 80 Remove-Item $env:systemroot\WindowsUpdate.log -ErrorAction SilentlyContinue + Write-Progress -Id 3 -ParentId 0 -Activity "Renaming/Removing Files" -Status "Completed" -PercentComplete 100 + + + if ($Aggressive) { + # Reset the Security Descriptors on the Windows Update Services + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Resetting the WU Service Security Descriptors..." -PercentComplete 25 + Write-Progress -Id 4 -ParentId 0 -Activity "Resetting the WU Service Security Descriptors" -Status "Resetting the BITS Security Descriptor..." -PercentComplete 0 + Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "bits", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)" + Write-Progress -Id 4 -ParentId 0 -Activity "Resetting the WU Service Security Descriptors" -Status "Resetting the wuauserv Security Descriptor..." -PercentComplete 50 + Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "wuauserv", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)" + Write-Progress -Id 4 -ParentId 0 -Activity "Resetting the WU Service Security Descriptors" -Status "Completed" -PercentComplete 100 + } -Write-Host "5. Resetting the Windows Update Services to default settings..." - Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "bits", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)" - Start-Process -NoNewWindow -FilePath "sc.exe" -ArgumentList "sdset", "wuauserv", "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)" + + # 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 = @( + "atl.dll", "urlmon.dll", "mshtml.dll", "shdocvw.dll", "browseui.dll", + "jscript.dll", "vbscript.dll", "scrrun.dll", "msxml.dll", "msxml3.dll", + "msxml6.dll", "actxprxy.dll", "softpub.dll", "wintrust.dll", "dssenh.dll", + "rsaenh.dll", "gpkcsp.dll", "sccbase.dll", "slbcsp.dll", "cryptdlg.dll", + "oleaut32.dll", "ole32.dll", "shell32.dll", "initpki.dll", "wuapi.dll", + "wuaueng.dll", "wuaueng1.dll", "wucltui.dll", "wups.dll", "wups2.dll", + "wuweb.dll", "qmgr.dll", "qmgrprxy.dll", "wucltux.dll", "muweb.dll", "wuwebv.dll" + ) + foreach ($dll in $DLLs) { + Write-Progress -Id 5 -ParentId 0 -Activity "Reregistering DLLs" -Status "Registering $dll..." -PercentComplete ($i / $DLLs.Count * 100) + $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 + + + # Remove the WSUS client settings + 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" -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 + } -Write-Host "6. Registering some DLLs..." -$DLLs = @( - "atl.dll", "urlmon.dll", "mshtml.dll", "shdocvw.dll", "browseui.dll", - "jscript.dll", "vbscript.dll", "scrrun.dll", "msxml.dll", "msxml3.dll", - "msxml6.dll", "actxprxy.dll", "softpub.dll", "wintrust.dll", "dssenh.dll", - "rsaenh.dll", "gpkcsp.dll", "sccbase.dll", "slbcsp.dll", "cryptdlg.dll", - "oleaut32.dll", "ole32.dll", "shell32.dll", "initpki.dll", "wuapi.dll", - "wuaueng.dll", "wuaueng1.dll", "wucltui.dll", "wups.dll", "wups2.dll", - "wuweb.dll", "qmgr.dll", "qmgrprxy.dll", "wucltux.dll", "muweb.dll", "wuwebv.dll" -) -foreach ($dll in $DLLs) { - Start-Process -NoNewWindow -FilePath "regsvr32.exe" -ArgumentList "/s", $dll -} - -Write-Host "7) Removing WSUS client settings..." -if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate") { - 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" -} - -Write-Host "8) Resetting the WinSock..." - 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" - -Write-Host "9) Delete all BITS jobs..." + + # 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" -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 + + + # Get and delete all BITS jobs + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Deleting BITS jobs..." -PercentComplete 75 + Write-Progress -Id 8 -ParentId 0 -Activity "Deleting BITS jobs" -Status "Deleting BITS jobs..." -PercentComplete 0 Get-BitsTransfer | Remove-BitsTransfer + Write-Progress -Id 8 -ParentId 0 -Activity "Deleting BITS jobs" -Status "Completed" -PercentComplete 100 -Write-Host "10) Attempting to install the Windows Update Agent..." -If ([System.Environment]::Is64BitOperatingSystem) { - Start-Process -NoNewWindow -FilePath "wusa" -ArgumentList "Windows8-RT-KB2937636-x64", "/quiet" -} -else { - Start-Process -NoNewWindow -FilePath "wusa" -ArgumentList "Windows8-RT-KB2937636-x86", "/quiet" -} - -Write-Host "11) Starting Windows Update Services..." - Start-Service -Name BITS - Start-Service -Name wuauserv - Start-Service -Name appidsvc - Start-Service -Name cryptsvc - -Write-Host "12) Forcing discovery..." - Start-Process -NoNewWindow -FilePath "wuauclt" -ArgumentList "/resetauthorization", "/detectnow" + # Change the startup type of the Windows Update Services and start them + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Starting Windows Update Services..." -PercentComplete 90 + Write-Progress -Id 9 -ParentId 0 -Activity "Starting Windows Update Services" -Status "Starting BITS..." -PercentComplete 0 + 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 + # 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 - Write-Host "Process complete. Please reboot your computer." + + # Force Windows Update to check for updates + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Forcing discovery..." -PercentComplete 95 + Write-Progress -Id 10 -ParentId 0 -Activity "Forcing discovery" -Status "Forcing discovery..." -PercentComplete 0 + (New-Object -ComObject Microsoft.Update.AutoUpdate).DetectNow() + Start-Process -NoNewWindow -FilePath "wuauclt" -ArgumentList "/resetauthorization", "/detectnow" + Write-Progress -Id 10 -ParentId 0 -Activity "Forcing discovery" -Status "Completed" -PercentComplete 100 + Write-Progress -Id 0 -Activity "Repairing Windows Update" -Status "Completed" -PercentComplete 100 $ButtonType = [System.Windows.MessageBoxButton]::OK $MessageboxTitle = "Reset Windows Update " @@ -86,4 +276,17 @@ Write-Host "12) Forcing discovery..." Write-Host "===============================================" Write-Host "-- Reset All Windows Update Settings to Stock -" Write-Host "===============================================" + + # 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