Script V2 for March 2021 update cleanup to fix printing issues

Windows Update[German]German blog reader bon-go sent me his revised PowerShell/batch script to uninstall the buggy March 2021 updates in Windows 10 that are causing the printing issues reported here on the blog. I'm posting the updated version of the script here on the blog – perhaps it will be of interest to someone.


Background: March 2021 printing issues

The Windows security updates from March 9, 2021, closed numerous vulnerabilities in the operating system. However, users reported significant printing issues shortly after installing the security updates (and Microsoft has confirmed these issues).

What followed was an update orgy that made many things worse. Above all, the installation of the fix updates was always associated with the risk that something went wrong. In response to my German blog post Windows 7/8.1/Server: Korrektur-Updates für Druckprobleme (März 2021), Andy offered in this comment to provide his generic PowerShell script to clean up the system from the problematic updates for a general use. I've published the 1st version of the PowerShell script within the blog post PowerShell Script to uninstall Windows Updates, to fix March 2021 Printing issues.

Updated script/batch

In this comment, blog reader bon-go mentioned his new version of the script he has written, because there were issues on some Windows systems. He has send me the new script/batch by mail with the notes below (thanks for sharing).

the original script worked fine for us for the most part – but depending on the Windows version not everywhere and not silent. Attached is the updated version for this and similar problems.

Note: this is a batch script which starts Powershell, so save as cmd.

The script runs once and any problematic updates must be uninstalled once with 'OK' (wusa with the parameter quiet or dism does not work everywhere, it also tries to hide the update immediately, works rather rarely – only for minor updates).

Then restart the PC as shown.

After the PC restart run the script again, everything runs as before. If you now try to uninstall the same update again, it is an endless loop, a timing problem when uninstalling and installing.

Normally the script finds the previously uninstalled problematic updates and hides them, this is also displayed.

If the hiding is not executed (no yellow line / no display) then:
– the update was withdrawn
– the PC needs a little bit longer until it wants to find it again
(start the script again after 1-2 min.)

Have fun …

Sounds promising. I received the script as an e-mail – here is the version that can be copied to an editor via clipboard and then saved as a batch file (.cmd).

;@echo off & setlocal & set localfname=%~f0
;Findstr -rbv ; %0 | powershell -c -

# removes the Windows updates from 03/2021 which cause printer problems 
#   as of 03/23/2021 'around noon', see also 
#   *
# # this batch + powershell script removes various updates based on the # name / KB numbers and hides them permanently, # the script needs local administrator rights, it asks for them
# # if the script has run once and updates to be removed were found # updates have been found, then be sure to restart the computer and
# directly after the restart run the script again, only # then the last updates to be removed will really be disappear. # # if also after repeated call again and again (the same)uninstalled,
# then manually intervene, clean the local Windows Update Cache
# (Script 02WindowsUpdatesLöschen.cmd),manually uninstall the updates # (if possible)and hide the updates(with wushowhide.diagcab) # # various parts of the script are just mangled and have been copied
# shamelessly copied from:
# * # the problematic updates / KB numbers (_without_ the 'KB' label) to be removed and hidden
$HotFixesToRemove=@("5000802", "5000808", "5000822", "5000809", "5000812", "5000803", "5000807", "5001567", "5001566", "5001568", "5001565") Function Main { [Cmdletbinding()] Param() Process { # test if the script was executed as administrator, if not then try restart with elevated privileges CheckAndRaiseElevation # remove the problematic updates
If( RemoveWrongHotfixes ) {

Write-Host "At least one Windows update was found which was uninstalled." Write-Host "Please wait, collecting information about pending updates..." HideWrongHotfixes Write-Host "The previously uninstalled Windows updates have been hidden as far as possible." Write-Host "Please restart the computer immediately and re-run the program" Write-Host "right after the start again." Write-Host "n case of an infinite loop (if this has already been done several times and this" Write-Host "message appears again and again then uninstall and hide manually." waitkey "Continue with any key, then restart manually [x]" | Out-Null } Else { # none of the problematic updates could be uninstalled anymore, try to find them # use the try-and-error method to hide them permanently Write-Host "None of the problematic updates is installed." Write-Host "Please wait, gather information about pending updates ..." HideWrongHotfixes Write-Host "The previously uninstalled Windows updates have been hidden as far as possible." WaitKey "The program can be terminated, continue with any key[x]" | Out-Null } } } Function WaitKey($___text){ Write-Host $___text $___x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null Return $___x } Function CheckAndRaiseElevation { [Cmdletbinding()] Param() Process { # Test for sufficient rights $IsElevated=([System.Security.Principal.WindowsPrincipal][System.Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) If( -not $IsElevated ) { Write-Host "Not enough user rights, elevate rights." Try { # try to run the batch with admin rights Start-Process -FilePath $env:localfname -Verb RunAs -ErrorAction SilentlyContinue } Catch { Write-Host "User refused to elevate rights - abort!" WaitKey "Press any key[x]" | Out-Null } Exit } # Write-Host "Program runs with admin rights." # change to the original program path if possible, also UNC and mapped network drives possible
Set-Location $(Split-Path -Parent $env:localfname) } } # removes if possible all problematic hotfixes specified as parameters
Function RemoveWrongHotfixes { [Cmdletbinding()] Param() Process { $ReturnVal=$False $InstalledHotFixes=$(Get-WmiObject -Class win32_quickfixengineering).HotFixID Write-Host "Ueberpruefe alle installierten Updates" Foreach( $InstalledHotFix in $InstalledHotFixes ) { Foreach($HotFixToRemove in $HotFixesToRemove) { If( $InstalledHotFix -match "$HotFixToRemove") { Write-Host "Das Update $InstalledHotFix wird entfernt" Start-Process -FilePath "wusa.exe" -Argumentlist "/Uninstall /KB:$HotFixToRemove /norestart" -PassThru -Wait | Out-Null $ReturnVal=$true } } } Return $ReturnVal } } # hide, if possible, problematic Hotfixes Function HideWrongHotfixes { [Cmdletbinding()] Param() Process { SearchForWindowsUpdates $ActUpdates=Get-WindowsUpdate Foreach( $ActUpdate in $ActUpdates ) { Foreach($HotFixToRemove in $HotFixesToRemove) { If( $ActUpdate.Title -match "$HotFixToRemove") { Write-Host "Update $($ActUpdate.Title) removed" Set-WindowsHiddenUpdate $ActUpdate -Hide $True -Verbose } } } } } Function Get-WindowsUpdate { [Cmdletbinding()] Param() Process { Try { Write-Verbose "Query all Windows Updates" $Session = New-Object -ComObject Microsoft.Update.Session $Searcher = $Session.CreateUpdateSearcher() $Criteria = "IsInstalled=0 and DeploymentAction='Installation' or IsPresent=1 and DeploymentAction='Uninstallation' or IsInstalled=1 and DeploymentAction='Installation' and RebootRequired=1 or IsInstalled=0 and DeploymentAction='Uninstallation' and RebootRequired=1" $SearchResult = $Searcher.Search($Criteria) $SearchResult.Updates } Catch { Write-Warning -Message "Query Windows Updates failed with error $($_.Exception.Message)" } } } Function SearchForWindowsUpdates { [Cmdletbinding()] Param() Process { # Define update criteria $Criteria = "IsInstalled=0" # Search for relevant updates $Searcher = New-Object -ComObject Microsoft.Update.Searcher $SearchResult = $Searcher.Search($Criteria).Updates } } Function SearchAndInstallWindowsUpdates { [Cmdletbinding()] Param() Process { # Define update criteria $Criteria = "IsInstalled=0" # Search for relevant updates $Searcher = New-Object -ComObject Microsoft.Update.Searcher $SearchResult = $Searcher.Search($Criteria).Updates # Download updates $Session = New-Object -ComObject Microsoft.Update.Session $Downloader = $Session.CreateUpdateDownloader() $Downloader.Updates = $SearchResult $Downloader.Download() $Installer = New-Object -ComObject Microsoft.Update.Installer $Installer.Updates = $SearchResult $Result = $Installer.Install() If ($Result.rebootRequired) { # shutdown.exe /t 0 /r } } } Function Remove-WindowsUpdate { [CmdletBinding()] param ( [parameter(Mandatory=$True)] $RemoveKB ) $Searcher = New-Object -ComObject Microsoft.Update.Searcher $RemoveCollection = New-Object -ComObject Microsoft.Update.UpdateColl # hole alle installierten Updates $SearchResult = $Searcher.Search("IsInstalled=1") # erzeuge Liste der zu loeschenden Updates wenn installiert $SearchResult.Updates | ? { $_.KBArticleIDs -in $RemoveKB } | % { $RemoveCollection.Add($_) } # loesche ... if ($RemoveCollection.Count -gt 0) { $Installer = New-Object -ComObject Microsoft.Update.Installer $Installer.Updates = $RemoveCollection $Installer.Uninstall() } else { Write-Warning "No matching Windows Updates found for:`n$($RemoveKB|Out-String)" } } # Bonus Function Show-WindowsUpdate { Get-WindowsUpdate | Select Title,isHidden, @{l='Size (MB)';e={'{0:N2}' -f ($_.MaxDownloadSize/1MB)}}, @{l='Published';e={$_.LastDeploymentChangeTime}} | Sort -Property Published } # # Show-WindowsUpdate # Show-WindowsUpdate | Where { $_.isHidden }| Out-GridView Function Set-WindowsHiddenUpdate { [Cmdletbinding()] Param( [Parameter(ValueFromPipeline=$true,Mandatory=$true)] [System.__ComObject[]]$Update, [Parameter(Mandatory=$true)] [boolean]$Hide ) Process { $Update | ForEach-Object -Process { if ((($_.pstypenames)[0] -eq 'System.__ComObject#{c1c2f21a-d2f4-4902-b5c6-8a081c19a890}') -or (($_.pstypenames)[0] -eq 'System.__ComObject#{70cf5c82-8642-42bb-9dbc-0cfd263c6c4f}') -or (($_.pstypenames)[0] -eq 'System.__ComObject#{918efd1e-b5d8-4c90-8540-aeb9bdc56f9d}')) { try { $_.isHidden = $Hide Write-Verbose -Message "Hide Update $($_.Title)" } catch { Write-Warning -Message "Hiding Windows Update failed, error $($_.Exception.Message)" } } else { Write-Warning -Message "Ignore passed object" } } } } # Examples: hide all still open Updates # Get-WindowsUpdate | Set-WindowsHiddenUpdate -Hide:$true -Verbose # Beispiel: verstecke alle noch offenene Definitionsupdates # Get-WindowsUpdate | Where { $_.Title -match 'Definitionsupdate' } | Set-WindowsHiddenUpdate -Hide:$false # Beispiel: verstecke alle noch offenene sicherheitsupdates # Get-WindowsUpdate | Where { $_.Title -match 'Sicherheitsupdate' } | Set-WindowsHiddenUpdate -Hide:$false # Beispiel: verstecke Browser Choice Updates # Get-WindowsUpdate | Where { $_.Title -match 'Microsoft Browser Choice Screen Update'} | Set-WindowsHiddenUpdate -Hide $true -Verbose main ;:BatchExit ;REM Note: this end of the batch script is executed immediately, it does not wait for the end of the Powershell! ;goto :eof # Date 22.03.2021 # # The errors are / were probably finally fixed with the following updates on 18.03 or 22.03.2021 # KB5001642 für Windows Server 2008 SP2 x64 (ESU) # # KB5001639 für Windows 7 SP1 x86 (ESU) # # KB5001639 für Windows 7 SP1 x64 (ESU) # # KB5001639 für Windows Server 2008 R2 (ESU) # # KB5001641 für Windows Server 2012 x64 # # KB5001640 für Windows 8.1 x86 # # KB5001640 für Windows 8.1 x64 # # KB5001640 für Windows Server 2012 R2 # # KB5001631 für Windows 10 1507 und Server 2016 # KB5001634 für Windows 10 1803 # KB5001638 für Windows 10 1809 und Server 2019 # KB5001648 für Windows 10 1909 # KB5001649 für Windows 10 2004 und 20H2 # # fehlerhaft waren bisher die Updates KB5000802, KB5000808, KB5000822, KB5000809, KB5000812, KB5000803, KB5000807, KB5001567, KB5001566, KB5001568, KB5001565

The original German edition of the script may be downloaded here. Have fun.


Cookies helps to fund this blog: Cookie settings

This entry was posted in issue, Windows and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *