Refresh Windows Updates Components: Patching Failure Super Script

Don’t you hate when monthly patches just won’t take? I ran into patch compliance issues in my past life as a MECM engineer. The script we’re about to review has helped me knock thousands of endpoints into patching compliance. We’re going to tackle 4 things in one go:

  1. Restart Windows Updates related services
  2. Backup and recreate Catroot2 and SoftwareDistribution folders
  3. Reregister related .dll files
  4. Kick off a reevaluation of MECM’s Software Update Deployment Evaluation task

I like to call this script a super punch; One, because I think that’s funny. Two, because we’re going to throw the kitchen sink at the problem. Let’s dive in.

TL;DR >>> GitHub

From the Top

Let’s start off by making some much needed variables. These will be the WMI objects for our Windows services, and the needed folder paths for Catroot2 and SoftwareDistribution.

$WUservice = Get-WmiObject -Class Win32_Service -Filter "Name='wuauserv'" 
$BITSservice = Get-WmiObject -Class Win32_Service -Filter "Name='BITS'"
$Cryptsvc = Get-WmiObject -Class Win32_service -Filter "Name='cryptsvc'"
$Msiserver = Get-WmiObject -Class Win32_service -Filter "Name='msiserver'"
$SFTDistBK = "c:\windows\SoftwareDistribution.bak"
$SFTDist = "c:\windows\SoftwareDistribution"
$CatrootDir= "c:\windows\system32\catroot2"
$CatrootDirBK = "C:\windows\system32\catroot2.old"

Catroot. Meow.

Next up! Let’s work on recreating the Catroot2 and SoftwareDistribution folders. We need to ensure that our Windows Updates related services are stopped. If they won’t stop, we’ll try to force them. If they don’t stop, we’ll relay back an error code to MECM so we know what to troubleshoot further.

For your weary eyes, I’ll only post a snippet here. Essentially, copy/paste this block of code for each Windows Update service variable (see above code) and change out the variables to the designated values. We also need to keep this in one big Try/Catch block, so please reference the GitHub link to see how I did this.

Try{
        #write-host "Stopping Services: $WUservice.Name"
        if($WUservice.State = "Running"){
            Stop-Service wuauserv
 
        }
        Else {
            Start-Service wuauserv 
            Start-Sleep -Seconds 10
            Stop-Service wuauserv 
        }
        } Catch {
            write-error "$WUservice.Name Service failed to stop" -ErrorId "3"
        }

Now, we’re going to attempt to recreate the discussed folders. Again, using more Try/Catch blocks and reporting back any error codes to MECM for further troubleshooting.

    $FolderFlagSF = Test-Path $SFTDistBK
    if($WUservice.State = "Stopped" -and ($BITSservice.State = "Stopped")){
        #write-host "Renaming SoftwareDistribution folder"
        Try {
            if(!($FolderFlagSF)){
                Rename-Item -path $SFTDist -NewName $SFTDistBK -Force 
            }
        Else {
            Remove-Item $SFTDistBK -Force -Recurse
            Rename-Item -Path $SFTDist -NewName $SFTDistBK -Force
            }
        } Catch [RenameItemIOError]{
            Write-error "Could not handle Software Distribution folder" -ErrorID "6"
        }
    }
    $FolderFlagCat = Test-Path $CatrootDirBK
    #write-host "Copying Catroot2 folder"
    Try{
        if(!($FolderFlagCat)) {
            New-Item -Path $CatrootDirBK -ItemType Directory
            Copy-Item -Path $CatrootDir -Destination $CatrootDirBK -Recurse 
            Remove-Item $CatrootDir -Force -Recurse
        }
        Else {
            Remove-Item $CatrootDirBK -Force -Recurse
            New-Item -Path $CatrootDirBK -ItemType Directory
            Copy-Item -Path $CatrootDir -Destination $CatrootDirBK -Recurse 
            Remove-Item $CatrootDir -Force -Recurse 
        }
    } Catch {
        write-error "Could not handle Catroot2 folder" -ErrorId "7"
    }

D-LL Cool J

Next step, registering .DLL files. I kept this relatively straight forward.

    regsvr32.exe /s atl.dll
    regsvr32.exe /s urlmon.dll
    regsvr32.exe /s mshtml.dll
    regsvr32.exe /s shdocvw.dll
    regsvr32.exe /s browseui.dll
    regsvr32.exe /s jscript.dll
    regsvr32.exe /s vbscript.dll
    regsvr32.exe /s scrrun.dll
    regsvr32.exe /s msxml.dll
    regsvr32.exe /s msxml3.dll
    regsvr32.exe /s msxml6.dll
    regsvr32.exe /s actxprxy.dll
    regsvr32.exe /s softpub.dll
    regsvr32.exe /s wintrust.dll
    regsvr32.exe /s dssenh.dll
    regsvr32.exe /s rsaenh.dll
    regsvr32.exe /s gpkcsp.dll
    regsvr32.exe /s sccbase.dll
    regsvr32.exe /s slbcsp.dll
    regsvr32.exe /s cryptdlg.dll
    regsvr32.exe /s oleaut32.dll
    regsvr32.exe /s ole32.dll
    regsvr32.exe /s shell32.dll
    regsvr32.exe /s initpki.dll
    regsvr32.exe /s wuapi.dll
    regsvr32.exe /s wuaueng.dll
    regsvr32.exe /s wuaueng1.dll
    regsvr32.exe /s wucltui.dll
    regsvr32.exe /s wups.dll
    regsvr32.exe /s wups2.dll
    regsvr32.exe /s wuweb.dll
    regsvr32.exe /s qmgr.dll
    regsvr32.exe /s qmgrprxy.dll
    regsvr32.exe /s wucltux.dll
    regsvr32.exe /s muweb.dll
    regsvr32.exe /s wuwebv.dll

Closing Time

Let’s wrap it up with ensuring that our services are started again.

 Start-Service wuauserv
 Start-Service BITS
 Start-Service cryptsvc
 Start-service msiserver 

And most importantly, sometimes the most complex problems require the simplest solutions; let’s kick off another Software Update Deployment Evaluation with the following command:

Invoke-WmiMethod -Namespace root\ccm -Class sms_client -Name TriggerSchedule "{00000000-0000-0000-0000-000000000108}" 

Final Words

This is a big one. It may be privy of you to just copy/paste the script from GitHub instead of following along, but at least you have a big explanation of what’s going on. As previously stated, I used to be a MECM engineer, and this script has helped me tackle those fickle machines that just don’t want to patch. I’m not saying this is a cure-all, but it definitely comes in handy!

And remember, kids:

This project is provided “as is” without any warranty of any kind, express or implied. Use it at your own risk. The authors and contributors are not responsible for any damage, data loss, or other issues that may arise from using this software. You are solely responsible for any actions taken based on this code.