This is the second post in the series, the first one can be found here: http://www.x9000.com/index.php/2016/02/08/windows-update-for-os-builders-part-1/
In this post we shall look as implementing a detection and download script for Windows Update. This code is the VBScript version of this script.
The PowerShell implementation will be available later in the series. However, if you are not using this for Windows 10 or Windows 2012 R2 or above, I’d recommend using this version due to the backward compatibility that VBScript brings.
VBScript has been working in all versions of Windows since Windows 2000 (Even Windows NT supported it as a add-on). This universality makes it a great candidate for tooling in creating builds. Indeed, anyone that has ever used and version of MDT will realised that a huge amount of the code is just VBScript.
Anyway, lets set the scene before we dump the code on you.
This code in it’s current form can just be run from the command line like this:-
This is the most basic usage and it will download the latest copy of WSUSSCN2.CAB (If it hasn’t already bee downloaded). It then performs a detection using this definition file and creates a folder called “Updates” into which the detected updates will be downloaded into a sub-folder for each download. I’ll come to what it looks like and how to use it later on.
The other althernative way to use this, one born of necessity, is to detect the patches required, but instead of downloading them, a file is created containing the download details. This file can then be transferred to somewhere else where the same script can read this file and create the folder full of updates. This has been essential when I’ve been working in secure locations with limited access to the internet. It means you can detect patches required on a secure locked down machine, but download the patches using a machine with a free internet connection. Probably doesn’t help most people, but if you work for a Bank or the Government you’ll recognise the problem.
To create the export file:
cscript WSUSDownload.vbs /e MyFile.txt
To download the patches now defined in MyFile.txt:
cscript WSUSDownload.vbs /i MyFile.txt
This method requires that you have already downloaded the WSUSSCN2.CAB file to the same folder as the script (It’s a secure environment remember, you probably can’t download the definition file)
NOTE: There is a section at the top of the script to define you proxy server details if you use one.
Anyway, time for some code. Be warned, read it, understand it and amend it to your needs. If you don’t undestand it, don’t use it as I won’t be there to hold you hands. The same is true for any code downloaded from the internet, it’s a dark and dangerous place.
Option Explicit 'Windows Updates Handler Script 'Author: Paul Prior 'Company: x9000.com Consulting Services Limited. 'Compatibility: Windows XP, WIndows 2003, WIndows Vista, Windows 7, Windows 2008, Windows 2008 R2, Windows 2012, Windows 2012 R2 'Additional Notes: Works for Windows 10 and Windows 2016 Preview but is sub-optimal as pkgmgr.exe is depricated. See the PowerShell version. 'Feel free to modify and reuse. Attribution would be appreciated. 'As always, test, test and test again. Don't blame me if your house burns down after using this script. Like any internet script, only use it once you understand what it does. Const ForWriting = 2 Const ForReading = 1 Dim ProxyName : ProxyName = "" ' Change if using a proxy server to something likre this: Dim ProxyName : ProxyName = "192.168.100.2:800" Dim objFSO : Set objFSO = CreateObject("Scripting.FileSystemObject") Dim objHTTP: Set objHTTP = CreateObject("WinHttp.WinHttpRequest.5.1") Dim Shell : Set Shell = CreateObject("WScript.Shell") Dim strWorkingDirectory : strWorkingDirectory = objFSO.GetParentFolderName(WScript.ScriptFullName) If Instr(1, WScript.FullName, "CScript", vbTextCompare) = 0 Then Shell.Run "cscript //NoLogo """ & WScript.ScriptFullName & """", 1, False WScript.Quit End If Dim Mode : Mode = "DetectAndDownload" Dim FileName : FileName = "" Dim objFile Dim Args : Set Args = Wscript.Arguments If Args.Count > 0 Then If InStr(UCase(Args(0)),"/I") > 0 Then Mode = "Import" FileName = Args(1) Else Mode = "Export" FileName = Args(1) End If End If If InStr(FileName,"\") = 0 Then FileName = strWorkingDirectory & "\" & FileName End If If Mode <> "Import" Then If Not objFSO.FileExists(strWorkingDirectory & "\WSUSSCN2.CAB") Then WScript.echo "Downloading WSUSSCN2.CAB definition file..." HTTPDownload "http://go.microsoft.com/fwlink/?LinkID=74689", strWorkingDirectory & "\WSUSSCN2.CAB" End If End If Dim objUpdateSession Dim objUpdateServiceManager Dim objUpdateService Dim objUpdateSearcher On Error Resume Next Set objUpdateSession = CreateObject("Microsoft.Update.Session") Set objUpdateServiceManager = CreateObject("Microsoft.Update.ServiceManager") Set objUpdateService = objUpdateServiceManager.AddScanPackageService("Offline Sync Service", strWorkingDirectory & "\WSUSSCN2.CAB") Set objUpdateSearcher = objUpdateSession.CreateUpdateSearcher() On Error Goto 0 If Mode="Export" Then Set objFile = objFSO.CreateTextFile(FileName, True) End If If Mode="Import" Then Set objFile = objFSO.OpenTextFile(FileName, ForReading) End If If Mode="Import" Then Dim ThisLine : ThisLine = "" Do Until objFile.AtEndOfStream ThisLine = objFile.ReadLine WScript.Echo ThisLine On Error Resume Next objFSO.CreateFolder("Updates") objFSO.CreateFolder(objFSO.GetParentFolderName(Split(ThisLine, vbTab)(1))) On Error Resume Next HTTPDownload Split(ThisLine, vbTab)(0), Split(ThisLine, vbTab)(1) Loop Else Wscript.Echo "Searching for updates..." & vbCRLF objUpdateSearcher.ServerSelection = 3 ' ssOthers objUpdateSearcher.ServiceID = objUpdateService.ServiceID Dim objSearchResult : Set objSearchResult = objUpdateSearcher.Search("IsInstalled=0") Dim objUpdates : Set objUpdates = objSearchResult.Updates If objSearchResult.Updates.Count = 0 Then WScript.Echo "There are no applicable updates." WScript.Quit End If Wscript.Echo "Offline Scan Results:" & vbCRLF Dim I For I = 0 to objSearchResult.Updates.Count-1 Dim objUpdate : Set objUpdate = objSearchResult.Updates.Item(I) WScript.Echo I + 1 & "> " & objUpdate.Title On Error Resume Next objFSO.CreateFolder("Updates") objFSO.CreateFolder("Updates\" & objUpdate.Title) objUpdate.AcceptEula On Error Goto 0 If objUpdate.BundledUpdates.Count > 0 Then Dim j For j = 0 To objUpdate.BundledUpdates.Count - 1 Dim k For k = 0 To objUpdate.BundledUpdates(j).DownloadContents.Count - 1 Dim DownloadFileName : DownloadFileName = Mid(objUpdate.BundledUpdates(j).DownloadContents(k).DownloadUrl, InstrRev(objUpdate.BundledUpdates(j).DownloadContents(k).DownloadUrl, "/") + 1) Dim Extension : Extension = Mid(DownloadFileName, InStrRev(DownloadFileName, ".")) DownloadFileName = Left(DownloadFileName, InStrRev(DownloadFileName, "_")-1) DownloadFileName = "Updates\" & objUpdate.Title & "\" & DownloadFileName & Extension HTTPDownload objUpdate.BundledUpdates(j).DownloadContents(k).DownloadUrl, DownloadFileName Next Next End If Next On Error Resume Next objFile.Close End If Wscript.Quit Sub HTTPDownload(URL, strFile) Select Case Mode Case "Export" objFile.WriteLine(URL & vbTab & strFile) Case Else If ProxyName <> "" Then objHTTP.SetProxy 2, ProxyName End If objHTTP.Option(6) = True objHTTP.Open "GET", URL, False objHTTP.Send Dim ADODB : Set ADODB = CreateObject("ADODB.Stream") ADODB.Type = 1 ADODB.Open ADODB.Write objHTTP.ResponseBody ADODB.SaveToFile strFile ADODB.Close End Select End Sub
Once you patches are downloaded, they look like this:
You’re probably wondering what you do with them to install them. If you are running XP or 2003 they are mostly in .EXE file formats, if you have Windows 7/2008 R2, you’ll see there are .EXE and mostly .CAB files. Windows 10 appears to only download .CAB files, but there could be the odd .EXE file. Those of you used to installing patches manually are probably used to the .MSU files, well what you have here is the equivalent of an expanded .MSU file. In the next episode of this series I’ll cover what we are going to do with these and provide another script that’ll install them for you.
Until next time, be safe, and don’t break stuff you can’t fix.