Thursday, September 16, 2010

Windows Update log scripting

** CAUTION NERD ALERT **

I have been working on a problem at work to add a list of updates required to be installed on our servers to my daily Powershell check script I have which runs each day. All the examples I had found online featured the script running a query against the WSUS server. I found this to a bit cumbersome for what I needed and it generally only gave me part of the picture required.

So instead I discovered that the windowsupdate.log file is in fact a tab separated file and with Powershell v2 you can easily import this. Once imported I rearranged to sort the newest lines first and then parse it to find the lines showing which updates are waiting.

I then strip those lines to get only the GUID for the update and query this against a WSUS server. This method seems to run fairly swiftly and quite well across WAN links.

If you want to use it just change the editable section at the top. Of course the script could be incorporated into a bigger script checking more than one computer. This is what it does in my daily server check.

I have also uploaded it to the TechNet Script Center Repository.

###
### Script to check WSUS updates to be installed on a given computer.
###
### Author: NomadTales
### Email: nomadtales [at] gmail [dot] com
### Twitter: @NomadTales
### Date: 16 Sept 2010
###
### License: Creative Commons Attribution-NonCommercial 3.0 Unported License
### LicenseURL: http://creativecommons.org/licenses/by-nc/3.0/
###
### The script parses the WindowsUpdate.log file to get a list of update GUIDs,
### then checks those GUIDs against the WSUS server. This method seems more
### acurate and simpler than polling the WSUS server directly.
###
### Please note there are probably better ways at scripting the string handling section.
### Let me know if so.
###


### Start editable section ###

$computer = "computer"       # The computer to check updates on
$systemdrv = "C"             # The System Drive
$windowsdir = "windows"      # The System Folder
$WSUSserver = "wsusserver"   # Your WSUS server
$WSUSserverportnum = "80"    # WSUS server port number
$wsusSSL = $false            # WSUS using SSL, if yes use $true

### End editable section ###


### START SCRIPT ###

## Reset variables - handy if you run the script multiple times from the editor

$updatesrequired = $null
$updates = $null
$updatelist = $null
$updatecount = 0

## Connect to the WSUS server

[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($WSUSserver,$wsusSSL,$WSUSserverportnum)

## Generate the path of the log file

$winupdatelog = "\\" + $computer + "\" + $systemdrv + "$\" + $windowsdir + "\windowsupdate.log"

## Import the log file and change the sorting to make newest first

$updates = import-csv $winupdatelog -delimiter `t -header "Date", "Time", "Code1", "Code2", "Action", "Description" `
    | sort @{Expression="Date";Descending=$true}, @{Expression="Time";Descending=$true}

## Parse the log file for the update GUID and query the WSUS server for the human friendly title

foreach ($update in $updates)
{
    if ($update.description -match "Added update {")
    {
        $updatecount++
        $updateidtemp = $update.description -replace ".*{"
        $updateid = $updateidtemp -replace "}.*"
        
        $updatesrequired = $wsus.GetUpdate([guid]$updateid)
        $updatelist += "{0}`n" -f $updatesrequired.title

    }
    
    if ($update.description -match "## START ## AU: Search for updates") {break}
   
}

## Add a total number of updates to the bottom

$updatelist += "`n"
$updatelist += "Total updates to install - {0}" -f $updatecount

## Display the updates required

$updatelist

### END SCRIPT ###