PowerShell: Removing Software Updates from Windows


Recently, I had the need to remove software updates from Windows servers in order to test out patching functionality in System Center Configuration Manager (SCCM / ConfigMgr). Since we’re currently deploying full patched operating system (OS) images, we didn’t really have any machines to test deploying software updates with. We’re currently working with non-production servers, so removing software updates for a few minutes and reinstalling them isn’t a big deal. I figured the easiest thing to do would be to simply remove any and all updates that could be removed (some can’t be uninstalled), so naturally, I wrote a script to handle this.

The Code

Unfortunately, the code itself isn’t all native PowerShell code. The only method I’m currently aware of to remove updates via command line is to use wusa.exe, which is built into Windows Server 2008 and Windows Server 2008 R2 (Vista and 7 as well). Wusa.exe has this handy /uninstall switch as well as a /kb switch, which allows you to specify the KB number of the update you’d like to remove! Of course, as with anything, you’ll want to enable logging, so for wusa, we’ll use the /log parameter. Finally, since we want to remove updates without prompting for confirmation, we’ll use the /quiet switch.

The basic command will look, quite simply, like this:

wusa.exe /uninstall /kb:123456 /quiet /log

Of course, now the challenge involves two things: 1) getting a list of installed updates, 2) retrieving the KB number from them! This is the part where wrapping the uninstall command with PowerShell comes in really handy! We’ll use a WMI class called Win32_QuickFixEngineering in the rootcimv2 namespace to list out all the installed updates, and then simply grab the HotfixID property from the instances of that class, and pop that into our wusa command line before actually executing it. Let’s take a look:

#  Author: Trevor Sullivan
#    Date: 5/25/11
# Purpose: Uninstall all software updates
#   Notes: wusa.exe kicks off asynchronously

# Get a list of all installed hotfixes
$PatchList = Get-WmiObject Win32_QuickFixEngineering -Namespace rootcimv2;

# Iterate over list of hotfixes
foreach ($Patch in $PatchList)
    # Write-Host $Patch.HotfixId

    # If the HotfixID property contains any text, remove it (some do, some don't)
    $KBNumber = $Patch.HotfixId.Replace("KB", "");

    # Write-Host $KBNumber

    # Build our command line for removing the update
    $RemovalCommand = "wusa.exe /uninstall /kb:$KBNumber /quiet /log /norestart";
    Write-Host ("Removing update with command: " + $RemovalCommand);

    # Invoke the command we built above
    Invoke-Expression -Command $RemovalCommand;

    # Wait for wusa.exe to finish and exit (wusa.exe actually leverages
    # TrustedInstaller.exe, so you won't see much activity within the wusa process)
    while (@(Get-Process wusa -ErrorAction SilentlyContinue).Count -ne 0)
        Start-Sleep 1
        Write-Host "Waiting for update removal to finish ..."

Once you’ve got this script saved off, you can deploy it to as many systems as you need to using a tool such as System Center Configuration Manager 2007! After you’ve removed the software updates from a bunch of your systems, you’re ready to test the deployment of software updates to them again!

Note: I already figured out a better way to handle this, I’m pretty sure, but just wanted to get this published for now. I think I found a more “API-friendly” method of performing a similar set of steps.