Tuesday, May 8, 2007

Scripting Windows Update Avoids Errors Fixes Problems

The windows update service on the PCs at work has gone mad. In the past the Windows Automatic Update has been a really trusted ally on our staff Windows XP Professional machines until a couple months after the release of Vista. Gosh I wonder why? Now occasionally it seems to use up all the processor cycles and suck up every last k of memory during its search phase. Some of our newer faster machines were just crashing.
Our Public PCs have been using a script to do windows updates since I discovered the script on the Microsoft Developers web site more than a year ago. To modify it for use on our staff PCs I wanted to change it to only download Security and Critical Updates and not to install any update that required a user to answer prompts. We will turn off windows update and add this script to the Maintenance script that runs when our staff users leave for the day.
I found the information I needed to modify the script on a great scripting resource, Active Experts, they have a page that shows all the properties and methods you can script for in windows update. Bookmark the Active Experts site, they are wonderful, I found on their site a property of a windows update that tells you if it requires user interaction and I Scripted a check for that property before installing so it would not install those updates.
The fabulous, Hey Scripting Guy, website gave me the method to force a script to run in the command line CSCRIPT shell.
    The script has been:
  • Modified for getting only security and critical updates
  • look for the comments that start with "MY MOD -"
  • The action starts at the bottom of script setting types of updates then calls the function DoWindowsUpdates. Get All updates, and other update types can be setup at the bottom of this script.
  • Modified to reject updates that need user interaction from installing
  • Modified to only run at the command line with cscript.
  • Tested in Windows XP Professional XP sp2 and Windows Vista Business
  • Tested with PCs set up for Windows Update and also Microsoft Update.
  • Don't copy the code from the screen to use Download the zip file here if you are brave enough to try it.
The Code____________

' Modified for getting only security and critical updates
' look for the comments that start with MY MOD -
' BE WARNED Don't even bother trying this or any other script you find online if you don't have test PCs to waste
' any issues you have with this script are your responsibility
' There is a MOD below that forces the script to run from the command line CSCRIPT
' Starts at the bottom of script setting types of update call the function DoWindowsUpdates
' All updates and other update types can be setup at the bottom of this script
' Modified to reject updates that need user interaction from installing
' Tested in WindowsXP Professional XP sp2 and Windows Vista
' Tested with PCs set up for Windows Update and Microsoft Update
' ------------------------------------------------------------------------------
' Filename: WindowsUpdates.vbs
' ------------------------------------------------------------------------------
' Description: Automatically downloads and installs relevant updates
' ------------------------------------------------------------------------------
' Version: Beta
' Notes:
' ------------------------------------------------------------------------------
' Copyright (C) Microsoft Corporation 2005, All Rights Reserved
' ------------------------------------------------------------------------------
Option Explicit
' MY MOD - had to define aka dim the last four items in the line below to go with my mods
Dim I, I2, oSession, oSearcher, oSearchResult, oUpdate, oUpdatesToDownload, oUpdatesToInstall, oDownloader, oInstaller, oInstallationResult, installcount, strPath, strCommand, objShell

' ------------------------------------------------------------------------------
' create objects
' ------------------------------------------------------------------------------
Set oSession = CreateObject("Microsoft.Update.Session")
Set oSearcher = oSession.CreateupdateSearcher()
' MY MOD - This 7 line group below forces the script to run in the Cscript command line where it belongs
' Because of the Option Explicit above we must add every variable to the DIM line above
Set objShell = CreateObject("Wscript.Shell")
If LCase(Right(Wscript.FullName, 11)) = "wscript.exe" Then
strPath = Wscript.ScriptFullName
strCommand = "%comspec% /k cscript " & Chr(34) & strPath & chr(34)
objShell.Run(strCommand)
Wscript.Quit
End If

Public Function DoWindowsUpdates

' ------------------------------------------------------------------------------
' search for updates
' ------------------------------------------------------------------------------
WScript.Echo "Searching for updates..." & vbCRLF
WScript.Echo "List of applicable items on the machine:"

I2=0
For I = 0 To oSearchResult.Updates.Count-1
Set oUpdate = oSearchResult.Updates.Item(I)
I2=I2+1
WScript.Echo I + 1 & "> " & oUpdate.Title
Next

If I2 = 0 Then
WScript.Echo "There are no applicable updates."
Exit Function
End If

' ------------------------------------------------------------------------------
' create collection of upates to download
' ------------------------------------------------------------------------------
WScript.Echo vbCRLF & "Creating collection of updates to download:"
Set oUpdatesToDownload = CreateObject("Microsoft.Update.UpdateColl")

For I = 0 to oSearchResult.Updates.Count-1
Set oUpdate = oSearchResult.Updates.Item(I)
WScript.Echo I + 1 & "> adding: " & oUpdate.Title
oUpdatesToDownload.Add(oUpdate)
Next

' ------------------------------------------------------------------------------
' download updates
' ------------------------------------------------------------------------------
WScript.Echo vbCRLF & "Downloading updates..."
Set oDownloader = oSession.CreateUpdateDownloader()
oDownloader.Updates = oUpdatesToDownload
oDownloader.Download()

' ------------------------------------------------------------------------------
' create a collection of downloaded updates to install
' ------------------------------------------------------------------------------
WScript.Echo vbCRLF & "Creating collection of downloaded updates to install:"
Set oUpdatesToInstall = CreateObject("Microsoft.Update.UpdateColl")
installcount = 0
' MY MOD - this if else in the loop checks to see if an update in the collection requires interaction and rejects it
For I = 0 To oSearchResult.Updates.Count-1
Set oUpdate = oSearchResult.Updates.Item(I)
If oUpdate.InstallationBehavior.CanRequestUserInput="True" Then
WScript.Echo I + 1 & "> Not Adding Needs User Input: " & oUpdate.Title
Else
WScript.Echo I + 1 & "> adding: " & oUpdate.Title
oUpdatesToInstall.Add(oUpdate)
installcount = installcount + 1
End if
Next

' ------------------------------------------------------------------------------
' install updates
' ------------------------------------------------------------------------------
' MY MOD - this if else in the loop prevents the script from halting if all updates are rejected
If installcount = 0 Then
WScript.Echo "No Updates to install"
Else
WScript.Echo "Installing updates..."
Set oInstaller = oSession.CreateUpdateInstaller()
oInstaller.Updates = oUpdatesToInstall
Set oInstallationResult = oInstaller.Install()
End If

' ------------------------------------------------------------------------------
' output results of install
' ------------------------------------------------------------------------------
' MY MOD - this if else in the loop prevents the script from halting if all updates are rejected
If installcount = 0 Then
WScript.Echo "No Updates Installed"
Else
WScript.Echo "Installation Result: " & oInstallationResult.ResultCode
WScript.Echo "Reboot Required: " & oInstallationResult.RebootRequired & vbCRLF
WScript.Echo "Listing of updates installed and individual installation results:"

For I = 0 to oUpdatesToInstall.Count - 1
WScript.Echo I + 1 & "> " & oUpdatesToInstall.Item(i).Title & ": " & oInstallationResult.GetUpdateResult(i).ResultCode
Next
End if
End Function

' MY MOD - Had to find the category IDs and Numbers with type listed again for the controlling sections below
'CATEGORY_SERVICEPACK = "68C5B0A3-D1A6-4553-AE49-01D3A7827828"
'CATEGORY_SECURITYPATCH = "0FA1201D-4330-4FA8-8AE9-B877473B6441"
'CATEGORY_CRITICALUPDATE = "E6CF1350-C01B-414D-A61F-263D14D133B4"
'CATEGORY_UPDATE = "CD5FFD1E-E932-4E3A-BF74-18BF0B1BBD83"
'CATEGORY_UPDATE_ROLLUP = "28BC880E-0592-4CBF-8F95-C79B17911D5F"


' Installation Types Control the script really starts down here then calls the function above
' This group of sections sets what kind of updates the script will search for using category ID Critical security etc.
' The last group that is commented out does not use a category ID and tries to get all updates good after you install a PC from scratch
' Above is the Collecting Downloading and installing work
' GROUP 1
Wscript.Echo "Downloading and Installing Critical Updates"
Set oSearchResult = oSearcher.Search("IsInstalled=0 and Type='Software' and CategoryIDs contains 'E6CF1350-C01B-414D-A61F-263D14D133B4'")
Call DoWindowsUpdates
wscript.echo vbCRLF
' GROUP 2
Wscript.Echo "Downloading and Installing Security Updates"
Set oSearchResult = oSearcher.Search("IsInstalled=0 and Type='Software' and CategoryIDs contains '0FA1201D-4330-4FA8-8AE9-B877473B6441'")
Call DoWindowsUpdates
wscript.echo vbCRLF
' GROUP 3
'wscript.echo "Downloading and Installing Service Packs"
'Set oSearchResult = oSearcher.Search("IsInstalled=0 and Type='Software' and CategoryIDs contains '68C5B0A3-D1A6-4553-AE49-01D3A7827828'")
'Call DoWindowsUpdates
'wscript.echo vbCRLF
' MY MOD - GROUP 4
'wscript.echo "Downloading and Installing Every Singe Update ever Devised"
'Set oSearchResult = oSearcher.Search("IsInstalled=0 and Type='Software'")
'Call DoWindowsUpdates
'wscript.echo vbCRLF

2 comments:

labmanager said...

Dude I think you need to update this and inclucde that great maintenence script that does all windows maintenence reboots checks the disk then shuts down.
That script is great!

labmanager said...

I know dude I rock.!