I don’t have a large environment to manage, but I do have a number of test boxes I try to keep up date using Windows Software Update Server (WSUS). Occasionally I’ve needed to manage things client-side. Unfortunately, there aren’t a lot of good tools, and nothing PowerShell-related that I’ve found so I wrote my own. At the end of this post you’ll be able to download a zip file with a self-extracting exe file to install my Windows Update module. Once installed, open an elevated PowerShell session and import the JH-WindowsUpdate module.
The module consists of the following commands:
The first challenge I tackled was finding an easier way to work with the client side event log. This text file, WindowsUpdate.log can get quite unwieldy very quickly. What I wanted was an object-based solution so I could find information. Get-WindowsUpdateLog takes the current log and turns each line into an object. Any lines that are just comment characters are stripped out. You end up with an object like this.
Component : Report
Message : Reporter successfully uploaded 2 events.
PID : 1100
Computername : SERENITY
TID : 17c0
Category : Normal
Datetime : 8/3/2010 7:47:26 AM
The function can also query remote computers and has a parameter to run as a job, which I typically do because processing the log file can take some time. I typically use it like this:
PS C:\> $wu=Get-WindowsUpdatelog
PS C:\> $wu | select DateTime,Component,Category,Message
When the file gets too big or whenever you feel like it, you can clear the log using Clear-WindowsUpdateLog. This will require restarting the WUAUSERV service. You can manage remote computers as well via WinRM. But you might want to first make a backup copy with Backup-WindowsUpdateLog. Be sure to look at command help and examples for everything.
The next part of the puzzle are the updates themselves. Fortunately there is a COM object that can be used to find and download Windows Updates.
#create session objects
$updateSession = New-Object -ComObject “Microsoft.Update.Session”
$updateSearcher = $updateSession.CreateUpdateSearcher()
The Get-WindowsUpdate command will find all recommended updates needed on the local computer. Or you can use -All.
The command doesn’t directly support remote computers, but you should be able to run it in a remote session. Installing updates uses almost the same approach with Install-WindowsUpdate. The default is to install Critical updates only. But you can install by severity, title or all.
If the update requires a reboot, the computer will not automatically reboot unless you specify -Reboot.
Unfortunately, installing updates must be done locally in an interactive session. There is a well known bug with this COM object that nobody has yet to find a way to beat. The best thing you can do for remote computers is to use SCHTASKS.EXE and remotely create a scheduled task to run the function on the remote computer. Of course you need to copy the module to the remote computer or at least load the function.
Please find a way to test all of this in a non-production environment. You can download the zip file with the self-extracting exe file here. Please post any followups, bugs or comments to this post.
Finally, and I’m trying something new here, but if you feel this module (or anything I’ve ever published for that matter) is of value to you or your organization, I hope you’ll consider adding something to my Paypal tip jar. Any contribution would be appreciated and allows me to continue developing solutions like this along with all my other PowerShell endeavors. Thank you.
UPDATE: I’ve already made an update. I’ve tweaked a few of the functions to fix a few bugs and hopefully improve performance. The original zip file with the self-extracting archive has been update. However, for people with mapped home drives the default install path will be a problem. You can always manually specify where to install per user, but anyone just clicking through will run into problems. Therefore, I’ve also created a simple zip file which you can download here. Manually extract the contents to a folder in your PSModulePath which you can check by looking at $env:PSModulePath.