It has become imperative for businesses to prioritize the security of their IT infrastructure. One of the foundational elements of this is ensuring that computers, and servers systems remain updated with the latest security patches. A significant proportion of cyberattacks exploit known vulnerabilities or flaws for which patches or fixes are already available.
For many acceptable reasons, specially in large company IT infrastructure, patch management solution like Microsoft WSUS, SCCM or Qualys for exemple, might not successfully patch all computers/servers in a requested short time (discovery issues, communication issues, client health, etc…). To fill this gap, IT Services might consider to create a parallele solution to patch faulty computers or servers. Windows Powershell can help to design your own patching process where the patch managment solution in place does not succeed.
On a Windows machine, computer or server, Windows OS give the ability to exploit the Windows Update Agent (WUA) through the Win32 WUA API. In PowerShell The WUA API can be accessed using Component Object Model interface (COM Objects) referered in Wuapi.dll.
Search Missing Windows Updates using ComObject
First of all, we need to create an Update Session, to do so let’s create a « Microsoft.Update.Session » COM Object inside a variable, and explore his members :
$objSession = New-Object -ComObject "Microsoft.Update.Session"
$objSession | Get-Member
Name MemberType Definition
---- ---------- ----------
CreateUpdateDownloader Method IUpdateDownloader CreateUpdateDownloader ()
CreateUpdateInstaller Method IUpdateInstaller CreateUpdateInstaller ()
CreateUpdateSearcher Method IUpdateSearcher CreateUpdateSearcher ()
CreateUpdateServiceManager Method IUpdateServiceManager2 CreateUpdateServiceManager ()
QueryHistory Method IUpdateHistoryEntryCollection QueryHistory (string criteria, int startIndex, int Count)
ClientApplicationID Property string ClientApplicationID () {get} {set}
ReadOnly Property bool ReadOnly () {get}
UserLocale Property uint UserLocale () {get} {set}
WebProxy Property IWebProxy WebProxy () {get} {set}
As we can see we get access to diferent usefull methods and properties.
Create your Update Searcher
We will use our initial Com Object « Microsoft.Update.Session » defined in $objSession, and call the method CreateUpdateSearcher(). This method will create an instance of object of type IUpdateSearcher.
$objSearcher = $objSession.CreateUpdateSearcher()
$objSearcher | Get-Member
Name MemberType Definition
---- ---------- ----------
BeginSearch Method ISearchJob BeginSearch (string criteria, IUnknown onCompleted, Variant state)
EndSearch Method ISearchResult EndSearch (ISearchJob searchJob)
EscapeString Method string EscapeString (string unescaped)
GetTotalHistoryCount Method int GetTotalHistoryCount ()
QueryHistory Method IUpdateHistoryEntryCollection QueryHistory (int startIndex, int Count)
Search Method ISearchResult Search (string criteria)
CanAutomaticallyUpgradeService Property bool CanAutomaticallyUpgradeService () {get} {set}
ClientApplicationID Property string ClientApplicationID () {get} {set}
IgnoreDownloadPriority Property bool IgnoreDownloadPriority () {get} {set}
IncludePotentiallySupersededUpdates Property bool IncludePotentiallySupersededUpdates () {get} {set}
Online Property bool Online () {get} {set}
SearchScope Property SearchScope SearchScope () {get} {set}
ServerSelection Property ServerSelection ServerSelection () {get} {set}
ServiceID Property string ServiceID () {get} {set}
Set properties to configure the behavior of your searcher
Now that we have an instance of IUpdateSearcher we have to configure diferent properties to control behavior of the searcher. In our case we need to set up the following properties with Int32 values.
ServerSelection => To determine where the updates are sourced from
The ServerSelection enumeration defines values that describe the type of server to use for an update search operation.
Here are the possible values for ServerSelection
:
- 0 (ssDefault): Search the default server for updates.
- 1 (ssManagedServer): Search only the managed server for updates, such as a Windows Server Update Services (WSUS) server that’s set up in an enterprise environment to distribute updates.
- 2 (ssWindowsUpdate): Search the Windows Update service over the Internet.
- 3 (ssOthers): Search another server, to be specified by other means.
In our case we will set the ServerSelection to 3 (ssOthers) in order to exclude the default server type, managed server type, and Windows Update service, in order to use the Microsoft Update service (which is not defined by a specific value).
$objSearcher.ServerSelection = 3
ServiceID => Represents a unique identifier (GUID) for the update service
With this property we can define which update service we want to use for the search. An update service is defined by his GUID. Basically the commonly used update services are :
- Windows Update: Windows Update service provide only Windows system patchs. The service will pull updates directly from internet. His GUID is consistent from Microsoft across all systems : 9482f4b4-e343-43b6-b170-9a65bc822c77
- Microsoft Update: Microsoft Update cover a larger scope whithin Windows system and Microsoft products such as Microsoft Office, Microsoft SQL server, etc… The service trigger the pull from Internet. His GUID is consistent from Microsoft across all systems : 7971f918-a847-4430-9279-4a52d1efe18d
- Windows Server Update Services (WSUS): If an enterprise has set up its own WSUS server, then the ServiceID would correspond to that WSUS instance. Each WSUS instance would typically have its own unique GUID.
In our case we will use the Microsoft Update service which provide us the most large scope of updates (Windows system, Office, etc…).
$objSearcher.ServiceID = '7971f918-a847-4430-9279-4a52d1efe18d'
Start searching missing updates
Now that our searcher is configured, we can start the search of update whith criterias.
As we saw above, the searcher object have a method called « Search ». This Search method accept criteria as filter to define which update you are looking for. Here is an exemple of search criteria to use for searching security updates that are not installed on the system :
$criteria = "IsInstalled=0 and Type='Software' and CategoryIDs contains '0fa1201d-4330-4fa8-8ae9-b877473b6441'"
The syntax used is similar to SQL, where you can define condition and logical operations. In this example we define not yet installed updates with "IsInstalled=0"
of type software "Type='Software'"
as opposed to driver updates, which would use Type='Driver'
. We filter the type of update with category ID '0fa1201d-4330-4fa8-8ae9-b877473b6441'
which correspond to Secrurity category update. You can find more details about types and categories classification with GUID on Microsoft online documentation.
Let’s start the search whitin a new variables that we will call $missingUpdates :
$missingUpdates = $objSearcher.Search($criteria)
After the search made, if updates are found, you will get a collection of updates returned by the service provider (Microsoft Udpdate in our case).
For example, here is an overview of an update object returned :
Title : Intel Corporation - Sensor - 5/10/2016 12:00:00 AM - 3.0.40.3258
AutoSelectOnWebSites : False
BundledUpdates : System.__ComObject
CanRequireSource : False
Categories : System.__ComObject
Deadline :
DeltaCompressedContentAvailable : False
DeltaCompressedContentPreferred : True
Description : Intel Corporation Sensor driver update released in May 2016
EulaAccepted : True
EulaText :
HandlerID : http://schemas.microsoft.com/msus/2002/12/UpdateHandlers/WindowsDriver
Identity : System.__ComObject
Image :
InstallationBehavior : System.__ComObject
IsBeta : False
IsDownloaded : False
IsHidden : False
IsInstalled : False
IsMandatory : False
IsUninstallable : False [...]
Install missing updates
Now that we get a collection of missing updates in our system, let’s see how we can install them to patch our computer. To do so, we need to introduce two new type of COM objects which are UpdateCollection
and IUpdateInstaller
. The UpdateCollection
object represents a collection of IUpdate
objects, essentially acting as a container to hold updates that you might want to download or install programmatically. The IUpdateInstaller
will give the ability to proceed to the installation of a specified updates collection set.
Let’s create an Update Collection inside a new variable and add on it our missing updates :
$updateCollection = New-Object -ComObject "Microsoft.Update.UpdateColl"
$missingUpdates.Updates | ForEach-Object { $updateCollection.Add($_) }
Our container is now ready…let’s create the installer using the initial session object, and inject it our update collection
$updateInstaller = $objSession.CreateUpdateInstaller()
$updateInstaller.Updates = $updateCollection
We can now start the installation :
$resultInstall = $updateInstaller.Install()
#Control the result of the installation
if ($installResult.ResultCode -eq 2) {
Write-Output "Updates installed successfully."
} else {
Write-Output "There was an issue installing the updates."
}
We’ve learned how to use Powershell and the Windows Update API to search an install missing windows updates.
I’ve made a Powershell module easy to use to help you to exploit the Windows Update Agent API, you can download it on github on following project : Powershell WUA.