Hey, Scripting Guy! How Can I Remove a Microsoft Update?

ScriptingGuy1

Hey, Scripting Guy! Question

Hey, Scripting Guy! You are not going to believe this. We recently deployed a Microsoft Update, and it is not working well for us. I tested it, of course, but for some reason it is not playing well with our systems. I now need to determine what the problem is, but in the meantime, I want to remove the update from all our systems. How can I write a script that will remove the Microsoft Update?

– MC

SpacerHey, Scripting Guy! Answer

Hi MC,

I am listening to the Buena Vista Social Club on my Zune. It does not matter how many times I listen to this album—man, it is sweet. The documentary is pretty good as well. It is cold and dreary outside, but the music warms my spirits like a day lying on the beach in late summer.

Oh, you would like to know how to uninstall an update. This is going to be a different kind of article today. The reason is that the script I am going to show you does not work for me. There is really not too much funny for me to say about this, because I am rather annoyed to be perfectly frank (or Ed). I spent more than five hours on this script, and in the end I do not think I would have been able to figure out the problem, if it had not been for having access to our internal support case files. In the hopes that I will save you the same frustration, we will go through the script. It is possible the script will work if you use it to uninstall an update that was deployed from a Microsoft Windows Server Update Services (WSUS) server, but I do not have one stuck under my desk, so I cannot test it.

This week we will be looking at using the Windows Update API to work with Windows Update. The Windows Update API is documented on MSDN. There is also a good collection of VBScripts that use the Windows Update API in the Script Center Script Repository. For information about manually configuring Windows Update on workstations, refer to this page. These scripts use Windows PowerShell. The Windows PowerShell getting started page has basic information for learning about Windows PowerShell and about downloading Windows PowerShell.

The UninstallUpdate.ps1 script is seen here (a VBScript version of this script is in the Script Center Script Repository):

$UpdateCollection = New-Object -ComObject Microsoft.Update.UpdateColl
$Searcher = New-Object -ComObject Microsoft.Update.Searcher

$updateID = “71535ae5-039f-482c-b242-6c5046414edf” $Result = $Searcher.Search(“UpdateID=’$updateID'”) $Updates = $Result.updates $updates “update count ” + $Updates.Count $UpdateCollection.Add($Updates.Item(0)) “Collection count ” + $UpdateCollection.Count

$Installer = New-Object -ComObject Microsoft.Update.Installer $Installer.Updates = $UpdateCollection $installer $Installer.UnInstall()

First the nitty-gritty details. After writing the UninstallUpdate.ps1 script, an error is returned when the script is run (the same is true of the VBScript version). The error that is returned is HResult 0x80240028. HResults can be looked up directly in the MSDN documentation. The result string is WU_E_UNINSTALL_NOT_ALLOWED. The description for the HResult is this: “The update could not be uninstalled because the request did not originate from a WSUS server.” The error message itself is seen here:

Image of the error message

 

So is the resolved error description right or not? It might be true, or it might not be true. I installed the update via the Microsoft Update Service on the Web. Does this use WSUS? Maybe the error is one of those bogus errors? After several hours of frustrated experimentation, I can assure you it is not a bogus error. The error in fact means exactly what it says: It cannot uninstall the update because the update was not installed via a WSUS server. The computer is considered to be an unmanaged workstation, and therefore the Uninstall method will not work. There is actually code that is used to inspect the workstation before calling the Uninstall method.

Remember the trick yesterday we used to gain more information about an error we were receiving? We looked in the System log of the Event Viewer. Well there are no errors in the Event Viewer related to this script. Bummer! Well, there is the Windows Update log file. Actually there may be two Windows Update log files; both found in the system root directory (C:\Windows).The first is the Windows Update.Log (it has a space in the name) file which is seen here:

Image of the Windows Update.Log

 

The contents of the Windows Update.Log file (with a space in the name) are sub-enthralling. The Windows Update.Log file you want to look at is the one without a space in the name: WindowsUpdate.Log. As seen in the next image, there is very detailed information related to each method call. In the log, the items that are listed as coming from COMAPI are related to actions arising from the script. You can see it performs a search, finds a single update, and then calls the Uninstall method. At this point, the exit code is the same one that we received from within the Windows PowerShell console.

Image of the detailed information related to each method call

 

The UninstallUpdate.ps1 script begins by creating a couple of objects. The Microsoft.Update.UpdateColl object and the Microsoft.Update.Searcher object were discussed in yesterday’s “Hey, Scripting Guy!” article.

After the UpdateColl and the Searcher objects are created, we specify the updateID and use the Searcher object to locate that particular update. The Result object contains a collection of update objects that are added to the UpdateColl object. (Again, all this was discussed in yesterdays Hey Scripting Guy! article.) This section of the code is seen here:

$UpdateCollection = New-Object -ComObject Microsoft.Update.UpdateColl
$Searcher = New-Object -ComObject Microsoft.Update.Searcher

$updateID = “71535ae5-039f-482c-b242-6c5046414edf” $Result = $Searcher.Search(“UpdateID=’$updateID'”) $Updates = $Result.updates $updates “update count ” + $Updates.Count $UpdateCollection.Add($Updates.Item(0)) “Collection count ” + $UpdateCollection.Count

Now we need to create the Installer object, add the UpdateCollection to the Updates property and call the Uninstall method. This section of code is similar to the code we used in yesterdays article:

$Installer = New-Object -ComObject Microsoft.Update.Installer
$Installer.Updates = $UpdateCollection
$installer
$Installer.UnInstall()

Well, MC, that is the way it goes sometimes when you are writing scripts. There are some things that should be easy, and then they end up taking a really long time. If you noticed, there is something like one line of difference between today’s script and yesterday’s script. I was hoping to get off easy today, but it did not work out like that. The good news is that tomorrow is Quick-Hits Friday! Woohoo! We love Quick-Hits Friday. Like a box of chocolates, you never know what you’re gonna get. See you tomorrow. Take care.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon