Manage Windows Update installations using Windows PowerShell
In most domains Windows Update are controlled by Group Policy and Windows Server Update Services (WSUS). For client computers, it`s common to download and install updates automatically. For servers, we want to control the installation of Windows Updates inside a scheduled maintenance window, and hence the Windows Update settings are configured not to automatically install updates.
If there are a few servers to manage, it won`t be that time consuming to log on to each server with Remote Desktop and do the Windows Update installations manually. In larger environments however, this won`t be an option, it must be automated in some way. While enterprise environments typically invest in a commercial product like BigFix for patch management, this might be overkill or too expensive for environments smaller than an enterprise.
To manage Windows Update in an automated way we can access the Windows Update Agent API using a COM-object called Microsoft.Update.Session. Using the New-Object cmdlet in Windows PowerShell, it`s easy to work with this COM-object. Based on this COM-object and portions of James O`Neill`s functions for managing Windows Update, I`ve written a PowerShell-script called Invoke-WindowsUpdate.
This script is intended to be used to download and install Windows Updates on servers. It runs like expected when invoked from a local computer, however, invoking the script using PowerShell Remoting like I was planning turned out to be problematic: Invoke-Command -ComputerName ServerA -FilePath ‘C:\ps-scripts\Windows Update\Invoke-WindowsUpdate.ps1′
This will return the following error message:
Exception calling “CreateUpdateDownloader” with “0″ argument(s): “Access is denied. (Exception from HRESULT: 0×80070005 E_ACCESSDENIED))”
This issue doesn`t seem to be related to PowerShell, as there are several others reporting the same problem in other languages like VBScript.
The common workaround is to schedule the script to run as a scheduled task running as SYSTEM. I`ve chosen to use this approach and to use PowerShell Remoting to invoke the scheduled task to run the script. An example:
$servers = Get-Content ‘C:\ps-scripts\Windows Update\BulkA.txt’
foreach ($server in $servers) {
Invoke-Command -Computer $server -ScriptBlock {schtasks /run /tn “PowerShell – download and install Windows Updates”}
}
To create the scheduled task I would recommend you to use Group Policy Preferences.
A few sample screenshots from my lab setup:
Although it`s possible to invoke the script on all servers in the domain at once using i.e. the Active Directory-module for PowerShell to get the server names, I would recommend to break down the installations in several bulks. This way you can control that all domain controllers doesn`t go offline at the same time and so on.
As you can see in the script it`s also possible to enable reporting to e-mail or file (HTML) to a central location, in addition to control whether the servers should reboot if required.
Planned improvements include nicer reports, Windows Update settings in the reports and if possible make the script work without having to use scheduled tasks. Suggestions for other improvements are always welcome.