I have written a VBS script that will install a specified hotfix on PCs that you specify. It requires that you have administrative privs on the remote machines. You must download
and extract "psexec.exe" to your %system% dir for this to work.
The script performs the following functions:
* Check to make sure app "psexec.exe" is installed in %system%
* Prompts admin for Machine ID, subnet to scan, or user-specified list.
* Prompts for patch to run (ie. Q824146.exe)
* Prompts for command-line switches
* Prompts for confirmation
* Verifies machines are on the network before installing.
* Verify machine is a Windows XP Professional Workstation before installing hotfix
* Verifies hotfix exists in location specified
* Executes and displays status in IE window.
* Logs results.
You can run this and cancel at anytime before you initialize the hotfix installation. Let me know if you have any questions.
-= j@ckle =-
'==========================================================================
'
' VBScript Source File -- Force Hotfix installation on Machines Specified
'
' NAME: installHotfix.vbs
'
' AUTHOR: Jason Spirko , Black & Veatch
' DATE : 09/19/2003
'
' COMMENT: Script will install hotfixes on machines specified
'
'==========================================================================
Option Explicit
' Define variables used throughout the script
'--------------------------------------------------------------------------
' System objects & variables
Dim oFSO, oShell, oNetwork
Dim oTempFile, oTextStream, oLog, oIPList, xCount, nRet
Dim sep, blank, iRootPath, sRootPath, sScriptFullName
Dim sScriptName, iFullNameLen, iNameLen, sScriptFolder
Dim sFileName, sLogFolder, oLogFolder, oNoReply
Dim oService, oPCSystem, oIE, oSystem, cComputers, rComputer, oGroup
Dim oUser, oADSysInfo
' Miscellaneous variables used throughout script
Dim sLog ' Script results log file (HotfixResults.log)
Dim sIPLog ' List of IP addresses to search
Dim sNoReplyLog ' List of machine that did not reply
Dim bSearchInactiveIPs ' True/False value
Dim bReplyFound ' Boolean variable if ping is successful (Default = false)
Dim sTagID ' B&V Computer TagID
Dim sIPAddress(2000) ' Array currently holds ~2000 computers (increase as necessary)
Dim sCurrentPC ' PC currently being searched
Dim sSubnet ' Subnet to search
Dim iIP ' IP Address incremental integer
Dim sTempFile ' Temp file used to store & analyze ping results
Dim sCommand ' Sends ping command
Dim sReadLine ' Read tempPing.txt to TextStream
Dim sHotfixPath ' Path to hotfix location
Dim sHotfixName ' Name of hotfix to install
Dim sHotfixCMD ' Hotfix command line arguments
Dim sSystemPath ' Remote PC System Path
Dim sOSType ' Lists OS
Dim nAns ' Confirmation answer
Dim sScanID ' Select subnet to patch
Dim sConfirm ' Confirmation string
Dim xPCCount ' Counts how many PCs were processed
Dim sUserSpecified ' User specified tagID list
Dim sYou ' Current username
Dim sUserDN ' Active Directory distinguished name
' Miscellaneous constants used throughout script
Const HKLM = &H80000002
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const DeleteReadOnly = True
Const YesButton = 6
Const QuestionMark = 32
Const YesNo = 4
' Set file system object variables
'--------------------------------------------------------------------------
Set oShell = CreateObject("Wscript.Shell"

Set oFSO = CreateObject("Scripting.FileSystemObject"

Set oNetwork = CreateObject("Wscript.Network"
' Set log file variables
'--------------------------------------------------------------------------
sep = "-------------------------------------------------------------------------------"
blank = " "
iRootPath = Len(sRootPath)
sScriptFullName = WScript.ScriptFullName
iFullNameLen = Len(sScriptFullName)
sFileName = WScript.ScriptName
iNameLen = Len(sFileName)
sScriptName = Left(sFileName, iNameLen - 4)
sScriptFolder = Left(sScriptFullName, iFullNameLen - (iNameLen + 1))
sLogFolder = sScriptFolder & "\" & sScriptName
sTagID = oNetwork.computername
' verify "psexec.exe" is installed on local machine
'--------------------------------------------------------------------------
If Not oFSO.FileExists("C:\Windows\System32\psexec.exe"

Then
MsgBox "You do not have the required files to complete a patch installation. Please download " & _
"psexec.exe from
"B&V ANAR - Patch Installation"
exitScript
End If
End If
' Prompt for subnet to patch
'--------------------------------------------------------------------------
sScanID = InputBox("Please enter the TAGID to patch or pick a selection below:" & vbCRLF & vbCRLF & _
" 1. Install patch by subnet" & vbCRLF & _
" 2. User specified list" & vbCRLF, "B&V ANAR - Patch Installation"

If sScanID = "" Then
MsgBox "You did not enter a valid selection or you clicked CANCEL. Patch installation cancelled.",, _
"B&V ANAR - Patch Installation"
exitScript
End If
' Create & specify log folder
'--------------------------------------------------------------------------
If Not oFSO.FolderExists(sLogFolder) Then Set oLogFolder = oFSO.CreateFolder(sLogFolder)
bSearchInactiveIPs = False ' Search machines in inactive IP list
Select Case sScanID
Case "1"
sSubnet = InputBox("Clients with IPs 40-239 will be processed on the subnet you specify. Please " & _
"enter the subnet below (ie. 10.183.41. ):", "B&V ANAR - Patch Installation"

sIPLog = "C:\_subnetIPs.tmp"
sLog = sLogFolder & "\hotfixResults_subnet.log"
sNoReplyLog = sLogFolder & "\noReply_subnet.log"
Case "2"
bSearchInactiveIPs = True
sIPLog = "C:\_UserSpecificIPs.tmp"
sLog = sLogFolder & "\hotfixResults_UserSpecified.log"
sNoReplyLog = sLogFolder & "\noReply_UserSpecified.log"
sUserSpecified = InputBox("Please enter the entire path to your list of tagIDs (ie. C:\tagIDs.txt). " & _
"When creating your list, please only enter one (1) tagID per line.", _
"B&V ANAR - Patch Installation"
' verify file exists
If Not oFSO.FileExists(sUserSpecified) Then
MsgBox "The file specified, " & sUserSpecified & " is invalid or does not exist. Patch installation cancelled.",,_
"B&V ANAR - Patch Installation"
exitScript
End If
Case Else
sIPLog = "C:\_reply" & sScanID& ".tmp"
sLog = sLogFolder & "\hotfixResults_" & sScanID & ".log"
sNoReplyLog = sLogFolder & "\noReply_" & sScanID & ".log"
End Select
sSystemPath = "\C$\Temp\"
' Prompt for hotfix name "Qxxxxxx.exe"
'--------------------------------------------------------------------------
sHotfixName = InputBox ("Please enter the hotfix Qnumber to install" & vbCRLF & "(ie. Q824146.exe):", _
"B&V ANAR - Patch Installation"

If sHotfixName = "" Then
MsgBox "You did not enter a filename or you clicked CANCEL. Patch installation cancelled.",, _
"B&V ANAR - Patch Installation"
exitScript
End If
' Prompt for hotfix path (default: S:\Service Packs\Hotfixes)
'--------------------------------------------------------------------------
sHotfixPath = InputBox("Please enter the path to the hotfix, or click OK to accept the default location.", _
"B&V ANAR - Path Installation", "S:\Service Packs\Hotfixes"

If sHotfixPath = "" Then
MsgBox "You did not enter a path or you clicked CANCEL. Patch installation cancelled.",, _
"B&V ANAR - Patch Installation"
exitScript
End If
' Prompt for command line arguments
'--------------------------------------------------------------------------
sHotfixCMD = InputBox ("Please enter any command line arguments you wish to pass during the installation. " & _
"Some of the more common switches are listed below:" & vbCRLF & vbCRLF & _
" -u" & vbTab & "unattended mode" & vbCRLF & _
" -f" & vbTab & "force programs to close when complete" & vbCRLF & _
" -n" & vbTab & "do not backup files for uninstall" & vbCRLF & _
" -o" & vbTab & "overwrite OEM files without prompting" & vbCRLF & _
" -z" & vbTab & "do not restart when installation is complete" & vbCRLF & _
" -q" & vbTab & "quiet mode (no user interaction)" & vbCRLF & _
" -l" & vbTab & "list installed Windows hotfixes" & vbCRLF & vbCRLF & _
"Please enter required switches (ie. -u -z):", "B&V ANAR - Patch Installation"
' Prompt for comfirmation
'--------------------------------------------------------------------------
Select Case sScanID
Case "1"
sConfirm = sSubnet & "40 - " & sSubnet & "239"
Case "2"
sConfirm = "User specified list"
Case Else
sConfirm = sScanID
End Select
nAns = oShell.Popup("Please confirm the following details:" & vbCRLF & vbCRLF & _
"Install on:" & vbCRLF & vbCRLF & _
vbTab & sConfirm & vbCRLF & vbCRLF & _
"Hotfix Number:" & vbCRLF & vbCRLF & _
vbTab & sHotfixName & " " & sHotfixCMD & vbCRLF & vbCRLF & _
"Hotfix location:" & vbCRLF & vbCRLF & _
vbTab & sHotfixPath & vbCRLF & vbCRLF & _
"Are you sure you want to install the hotfix listed above?",, "B&V ANAR - Patch Installation", _
QuestionMark + YesNo)
If nAns <> YesButton Then
MsgBox "Patch Installation cancelled by user.",,"B&V ANAR - Patch Installation"
exitScript
End If
' Verify that Hotfix is located in S:\Hotfixes
'--------------------------------------------------------------------------
If Not oFSO.FileExists(sHotfixPath & "\" & sHotfixName) Then
MsgBox "Could not find required hotfix: " & sHotfixPath & "\" & sHotfixName & _
". Patch installation cancelled.",,"B&V ANAR - Patch Installation"
exitScript
End If
' Create log file
'--------------------------------------------------------------------------
Set oLog = oFSO.OpenTextFile(sLog, ForWriting, True)
writelog(sep)
writelog(Now & ":" & vbTab & "Script " & sScriptName & " Started"

writelog(sep)
writelog(blank)
writelog("Hotfix Number: " & sHotfixName)
writelog("Hotfix Location: " & sHotfixPath)
Select Case sScanID
Case "1"
writelog("Install on: " & sSubnet & "40 - " & sSubnet & "239"

Case "2"
writelog("Install on: User specified list"

Case Else
writelog("Install on: " & sScanID)
End Select
writelog(blank)
writelog(sep)
writelog(blank)
writelog(blank)
'**************************************************************************
' Specify subnets to search { format: setSubnet("XXX.XXX.XXX."

}
'**************************************************************************
Set oIPList = oFSO.OpenTextFile(sIPLog, ForWriting, True)
Select Case sScanID
Case ""
MsgBox "No machines selected. Patch installation cancelled.",, "B&V ANAR - Patch Installation"
Case "1"
setSubnet(sSubnet)
Case "2"
Case Else
oIPList.WriteLine(sScanID)
End Select
oIPList.Close
'**************************************************************************
'**************************************************************************
' initialize IE
'--------------------------------------------------------------------------
setupIE
xPCCount = 0
' write initial header in IE
writeIEBold("<font face=""Arial"" color=#0000FF size=2>Patch installation initiated at " & Now() & ".</font><br>"
' Scan and patch machine
'--------------------------------------------------------------------------
If bSearchInactiveIPs = True Then
' Search for inactive computers
oFSO.CopyFile sUserSpecified, sIPLog
oFSO.DeleteFile(sNoReplyLog)
Set oIPList = oFSO.OpenTextFile(sIPLog, ForReading, True)
Set oNoReply = oFSO.OpenTextFile(sNoReplyLog, ForWriting, True)
Do While oIPList.AtEndOfStream <> True
sIPAddress(xCount) = oIPList.ReadLine
sCurrentPC = sIPAddress(xCount)
IsValidPing(sCurrentPC)
xCount = xCount + 1
Loop
oIPList.Close
oNoReply.Close
Else
' Search for specified computers
Set oIPList = oFSO.OpenTextFile(sIPLog, ForReading, True)
Set oNoReply = oFSO.OpenTextFile(sNoReplyLog, ForWriting, True)
Do While oIPList.AtEndOfStream <> True
sIPAddress(xCount) = oIPList.ReadLine
sCurrentPC = sIPAddress(xCount)
IsValidPing(sCurrentPC)
xCount = xCount + 1
Loop
oIPList.Close
oNoReply.Close
End If
' Delete _listIPAddresses.tmp when complete
'--------------------------------------------------------------------------
oFSO.DeleteFile(sIPLog)
' Add final lines in log file and close
'--------------------------------------------------------------------------
writelog(blank)
writelog(blank)
writelog(sep)
writelog(Now & ":" & vbTab & "Script " & sScriptName & " Processing Complete"

writelog(sep)
WScript.Sleep 4000
oLog.close
' Add final lines in status windows and close
'--------------------------------------------------------------------------
writeIEBold("<font face=""Arial"" size=2>" & xPCCount & " machines processed.</font>"

writeIEBold("<font face=""Arial"" color=#0000FF size=2>Patch installation completed at " & Now() & ".</font><br><br>"

writeIE("Please view the following log files for more information:<br>"

writeIEBold("Hotfix Results:"

writeIE(sLog & "<br>"

writeIEBold("No Reply:"

writeIE(sNoReplyLog & "<br>"

exitScript
' Functions and subs go here
'==========================================================================
'** Function ****************
' writelog
' writes a line to log file
'****************************
Function writelog(input)
oLog.Writeline input
End Function
'** Function ****************
' writereply
' writes a line to log file
'****************************
Function writereply(input)
oNoReply.Writeline input
End Function
'** Function ********************************
' setSubnet
' searches DHCP clients in specified subnet
'********************************************
Function setSubnet(sSubnet)
' Start DHCP scope at 40
iIP = 40
' loop thru all IPs until 240
Do While Not iIP = 240
oIPList.WriteLine(sSubnet & iIP)
' Increment IP address + 1
iIP = iIP + 1
Loop
End Function
'** Function ********************************
' IsValidPing
' checks if machine is available
'********************************************
Function IsValidPing(sCurrentPC)
' Set default return value.
bReplyFound = False
Select Case sScanID
Case "1"
sTempFile = "C:\_ping_subnet.tmp"
Case "2"
sTempFile = "C:\_ping_UserSpecified.tmp"
Case Else
sTempFile = "C:\_ping_" & sScanID & ".tmp"
End Select
' Create command line to ping and save results to a temp file.
sCommand = "cmd /c ping -n 1 -w 500 " & sCurrentPC & " > " & sTempFile
' Execute the command
oShell.run sCommand,0,True
' Open the temp file.
Set oTempFile = oFSO.OpenTextFile(sTempFile, ForReading, True)
' Loop through the temp file to see if ping was successful.
Do While oTempFile.AtEndOfStream <> True
sReadLine = oTempFile.ReadLine
' if "reply from" is found in temp file then ping was successful.
If Instr(LCase(sReadLine), "reply from"

> 0 Then
bReplyFound = True
Exit Do
End If
Loop
If bReplyFound = True Then
'WScript.Echo "Processing : " & sCurrentPC
installHotfix(sCurrentPC)
Else
'WScript.Echo "Error : " & sCurrentPC & " machine unavailable."
writeIEBold("<font color=#FF0000>Error : " & sCurrentPC & " is unavailable.</font><br>"

writereply(sCurrentPC)
writelog("Error : " & sCurrentPC & " is unavailable."

End If
' Close temp file and release objects.
oTempFile.Close
oFSO.DeleteFile(sTempFile)
Set oTempFile = Nothing
End Function
'** Function ********************************
' installHotfix
' searches DHCP clients in specified subnet
'********************************************
Function installHotfix(sCurrentPC)
' check operating system
Set oSystem = GetObject("winMgmts:\\" & sCurrentPC)
Set cComputers = oSystem.ExecQuery("SELECT * FROM Win32_OperatingSystem"
For Each rComputer In cComputers
sOSType = rComputer.Caption
Next
'Get tagID & username
Set oService = GetObject("winMgmts:\\" & sCurrentPC & "\root\cimv2"

Set oPCSystem = oService.InstancesOf("Win32_ComputerSystem"
For Each oPCSystem In oPCSystem
sTagID = oPCSystem.Name
Next
' if OS = Windows XP then continue
If sOSType = "Microsoft Windows XP Professional" Then
' display current PC being processed
writeIEBold("Now processing: " & sTagID)
'oIE.Document.write "<ul>"
' copy hotfix & shutdown script to remote machine
writeIEList("Copying necessary files..."

oFSO.CopyFile sHotfixPath & "\" & sHotfixName, "\\" & sCurrentPC & "\C$\Temp\" & sHotfixName, True
oFSO.CopyFile _
"\\NA\Data\Branch\AnnArbor\Departments\DEPT-3545\Public\Support\Installs\Scripts\shutdown_PC.vbe", _
"\\" & sCurrentPC & "\C$\Windows\System32\shutdown_PC.vbe", True
' Run hotfix on remote machine
writeIEList("Executing hotfix..."

sCommand = "psexec \\" & sCurrentPC & " C:\Temp\" & sHotfixName & " " & sHotfixCMD
oShell.Run sCommand, 0, True
' delete hotfix file
writeIEList("Removing temporary files..."

oFSO.DeleteFile("\\" & sCurrentPC & "\C$\Temp\" & sHotfixName)
' schedule machine reboot
writeIEList("Scheduling machine reboot & midnight..."

'oIE.Document.write "</ul>"
writelog (sTagID & " : " & sHotfixName & " : Install complete"

sCommand = "AT \\" & sCurrentPC & " 0:00 shutdown_PC.vbe"
oShell.Run sCommand, 0, True
writeIEBold("Processing complete: " & sTagID)
oIE.Document.write "<br>"
Else
writelog (sTagID & ": non-Windows XP machine"

End If
xPCCount = xPCCount + 1
End Function
'** Sub ***************************
' exitScript
' Exit script and release objects
'**********************************
Sub exitScript
Set oFSO = Nothing
Set oShell = Nothing
Set oNetwork = Nothing
Set oSystem = Nothing
Set oTempFile = Nothing
Set oTextStream = Nothing
Set oLog = Nothing
Set oIPList = Nothing
Set oLogFolder = Nothing
Set oNoReply = Nothing
Set oService = Nothing
Set oPCSystem = Nothing
Set oIE = Nothing
Set oGroup = Nothing
Set oUser = Nothing
Set oADSysInfo = Nothing
WScript.Quit
End Sub
'** Sub ********************
' setupIE
' Initialize IE environment
'****************************
Sub setupIE
Set oIE = CreateObject("InternetExplorer.Application"

oIE.MenuBar = False
oIE.ToolBar = 0
oIE.Height = 300
oIE.Width = 550
oIE.StatusBar = False
oIE.Navigate "about:blank"
oIE.Visible = True
oIE.Document.write "<title>B&V ANAR - Patch Installation</Title>"
oIE.Document.write "</head><body>"
oIE.Document.write "<p align=""left"">"
End Sub
'** Function ***************
' writeIE
' Writes line in IE
'****************************
Function writeIE(input)
oIE.Document.write "<font face=""Arial"" size=2>" & vbTab & input & "</font><br>"
End Function
'** Function ********************
' writeIEList
' Writes line in IE with bullets
'*********************************
Function writeIEList(input)
oIE.Document.write "<li><font face=""Arial"" size=2>" & vbTab & input & "</font></li><br>"
End Function
'** Function ***************
' writeIEBold
' Writes line in IE
'****************************
Function writeIEBold(input)
oIE.Document.write "<strong><font face=""Arial"" size=2>" & input & "</font></strong><br>"
End function
' ******************************* END OF SCRIPT *******************************