TheTAZZone - Internet Chaos

Mass EXE deployment

ORIGINALLY POSTED BY TALEN FOR THETAZZONE/TAZFORUM HERE

Do not use, republish, in whole or in part, without the consent of the Author. TheTAZZone policy is that Authors retain the rights to the work they submit and/or post…we do not sell, publish, transmit, or have the right to give permission for such…TheTAZZone merely retains the right to use, retain, and publish submitted work within it’s Network

Please refer to the original post as not all the script may be visible here.

Often times a rather useful utility is packaged as an EXE and you’d like to run it against multiple workstations. That’s easy enough, but can you do it with full accounting?

Here’s a pair of scripts (to be used together) that I’ve developed that will do just that. You’ll also need SOON.EXE, LOGEVENT.EXE, Microsoft Excel, and a text file containing the names of your workstations, one on each line (and administrative access from the command line).

2008.03.29 Edit: I added some error handling to the script to deal with machines that weren’t on the network (as I don’t always know which ones are and which ones aren’t at any given time). I also found that the functions using the WMI queries would hang on the odd workstation that didn’t have WMI configured correctly, so added error handling for that as well. Finally, I added a bit of feedback to the script, I like to know what the script is doing and where it is in execution. I’ve replaced deployEXE.VBS with the new script. (I’m making further changes to runEXE.VBS, I’ll post it when I’m done.)

2008.03.31 Edit: I modified the runEXE.VBS script to be OS aware, since the EVENTCREATE utility isn’t built into Windows 2000. Instead, the script makes use of the LOGEVENT.EXE utility (found in the Windows 2000 Resource Kit) located on a share. I also decided to add a bit of “debugging” output to a text file. If it’s unnecessary in your particular circumstance, feel free to remove it.

Script 1:

Code: Select all
' File Name:   deployEXE.VBS
' Script Name:   deployEXE.VBS
' Created:      2008.03.12
' Author:      Rob Durkin, STuladhar, Talen
' E-mail:
' ------------------------------------------------------------------------------
' ARGUMENTS :
'   None
' ------------------------------------------------------------------------------

' ------------------------------------------------------------------------------
' PURPOSE :
'   Runs an executable on a remote workstation from a network share and logs the
'   result to an Excel spreadsheet.
'   - The main script will copy the EXE file and one other VBS script to the
'   target machine.
'   - The main script will execute SOON.EXE (available via download from
'   Microsoft) to schedule the second VBS script on the target machine.
'   - The second script will execute the EXE and make an entry in the
'   application log based on success or failure.
'   - The main script will then follow up and parse through the application log
'   and check the result of the EXE.
'   * NOTE: Excel must be installed on the workstation the script is run from.
' ------------------------------------------------------------------------------
'
' ------------------------------------------------------------------------------
' REVISION HISTORY :
' Date:      2008.03.28
' Time:
' Issue:      Needed error handling in the event of unreachable workstations or
'            other issues that would cause a workstation not to respond.
' Solution:   Added workstation availability checks using ping as well as an On
'            Error trap around the call to the Functions using WMI queries.
'
' ------------------------------------------------------------------------------

Option Explicit

' ------------------------------------------------------------------------------
' FUNCTION LISTINGS
' ------------------------------------------------------------------------------
' Function:   getInstallStatus
' Created:   2007.12.26
' Author:   STuladhar
' Arguments: strSuccess & strFailed, defined in verifyInstall subroutine.
' ------------------------------------------------------------------------------
' Purpose:
'   Checks the installation status in the remote workstation Application log.
' ------------------------------------------------------------------------------
Function getInstallStatus(strSuccess, strFailed, strComputer)
Dim intCount, intFailed

intCount = getEventLogCount(strSuccess, strComputer)

If intCount > 0 Then
getInstallStatus = "P"
Else
intFailed = getEventLogCount(strFailed, strComputer)
If intFailed > 0 Then
getInstallStatus = "F"
Else
getInstallStatus = "U"
End If
End If
End Function

' ------------------------------------------------------------------------------
' Function:   getEventLogCount
' Created:   2007.12.26
' Author:   STuladhar
' Arguments: strWQL, success or failure WQL defined in verifyInstall subroutine.
' ------------------------------------------------------------------------------
' Purpose:
'   Counts the number of events in an event log matching specific criteria
'   defined via WQL query (see subVerifyInstall).
' ------------------------------------------------------------------------------
Function getEventLogCount(strWQL, strComputer)
Dim colLoggedEvents
Dim objWMISvc

Set objWMISvc = GetObject("winmgmts:" & "{(Security)}\\" & strComputer & _
"\root\cimv2")
Set colLoggedEvents = objWMISvc.ExecQuery(strWQL)

getEventLogCount = colLoggedEvents.Count
End Function

' ------------------------------------------------------------------------------
' Function:   getEventLogMsg
' Created:   2007.12.26
' Author:   STuladhar
' Arguments: strWQL, success or failure WQL defined in verifyInstall subroutine.
' ------------------------------------------------------------------------------
' Purpose:
'   Collects the event log descriptions for each event log entry collected
'   according to the WQL query in Function getEventLogCount.
' ------------------------------------------------------------------------------
Function getEventLogMsg(strWQL, strComputer)
Dim colLoggedEvents
Dim objEvent, objWMISvc
Dim strMsg

Set objWMISvc = GetObject("winmgmts:" & "{(Security)}\\" & strComputer & _
"\root\cimv2")
Set colLoggedEvents = objWMISvc.ExecQuery(strWQL)

For Each objEvent In colLoggedEvents
strMsg = strMsg & chr(13) & objEvent.Message
Next

' This is the length of the event log description. Change the length as
' necessary (the event log descriptions are defined in runEXE.VBS)
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
getEventLogMsg = Left(strMsg, 255)
End Function

' ==============================================================================
' SCRIPT BODY
' ==============================================================================
Dim a, b, DD, MM, YYYY, vDy, vMo
Dim errReturn, FileName, intProcessID
Dim strExcelFile, strCmd, strComputer, strDest01, strDest02, strFile01
Dim strFile02, strList, strPing, strText, strVBS, strWkstn
Dim objExcel, objExecObject, objFileCopy, objFSO, objSheet, objShell, objTxtFile

Const ForReading = 1, ForWriting = 2, ForAppending = 8

' Bind to the file system object
Set objFSO = CreateObject("Scripting.FileSystemObject")

' Bind to the shell object
Set objShell = CreateObject("WScript.Shell")

' Call the subroutines in the correct order (they're listed in alphabetical
' in the script body)
subGetDate
subCreateExcelWorkbook
subMain
' Pause the script for two and a half minutes (unnecessary if deploying to a
' large number of workstations)
WScript.Echo "Pausing script for 2 minutes and 30 seconds at " & Now
WScript.Sleep 150000
subVerifyInstall
subCleanUp

Sub subCleanUp
WScript.Echo "Beginning clean up..."

' Save the spreadsheet and close the workbook
objExcel.ActiveWorkbook.SaveAs strExcelFile
objExcel.ActiveWorkbook.Close
objExcel.Application.Quit

WScript.Echo "Clean up and script complete."
End Sub

Sub subCreateExcelWorkbook
' Define the filename for the Excel file, change to .XLSX if using Excel 2007
strExcelFile = YYYY & vMo & vDy & "deployEXE.XLS"

' Bind to the Excel application object
Set objExcel = CreateObject("Excel.Application")

' If Excel not found, exit script
If (Err.Number <> 0) Then
WScript.Echo "Excel application not found."
WScript.Quit
End If

' Create a new workbook
objExcel.Workbooks.Add

' Bind to and name the first worksheet in the workbook
Set objSheet = objExcel.ActiveWorkbook.Worksheets(1)
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
objSheet.Name = "Worksheet Name"

' Populate spreadsheet cells (column headings) with user-defined attributes
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
objSheet.Cells(1, 1).Value = "Target Computer"
objSheet.Cells(1, 2).Value = "Time"
objSheet.Cells(1, 3).Value = "Ping"
objSheet.Cells(1, 4).Value = "SOON Execution"
objSheet.Cells(1, 5).Value = "Utility Execution"
End Sub

' This subroutine gets the year, month and day for the purposes of building the
' Excel filename in the subroutine subCreateExcelWorkbook
Sub subGetDate
YYYY = Year(Now)
MM = Month(Now)
DD = Day(Now)

If MM < 10 Then
vMo = "0" & MM
Else
vMo = MM
End If

If DD < 10 Then
vDy = "0" & DD
Else
vDy = DD
End If
End Sub

Sub subMain
WScript.Echo "Deploying software..."

' Variable containing UNC path to workstation list text file
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strList = "\\SERVER\Share" & _
"\workstationList.TXT"

' Variable containing UNC path to executable that needs to be copied to
' remote machine
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strFile01 = "\\SERVER\Share" & _
"\Utility.EXE"

' Variable containing UNC path to script that needs to be copied to remote
' machine
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strFile02 = "\\SERVER\Share" & _
"\runEXE.VBS"

' Variable containing script that will launch executable on remote machine
strVBS = "runEXE.VBS"

' Open the text file containing the list of workstation names for reading
Set objTxtFile = objFSO.OpenTextFile(strList, ForReading)

' Set the Excel row variable to start on the second row
a = 2

' Begin looping through workstations
Do Until objTxtFile.AtEndOfStream
' Get machine name from text file (and remove any whitespaces)
strWkstn = Trim(objTxtFile.ReadLine())

' Ping the workstation, skipping it if it is unreachable on the network
strPing = "%comspec% /c ping -n 3 -w 1000 " & strWkstn & ""
Set objExecObject = objShell.Exec(strPing)

Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadAll()

If InStr(strText, "Reply") > 0 Then
WScript.Echo "Starting on " & strWkstn & "..."

' UNC path to destination where executable and script needs to be
' copied to on the remote machine
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strDest01 = "\\" & strWkstn & "\C$" & _
"\Utility.EXE"
strDest02 = "\\" & strWkstn & "\C$" & _
"\runEXE.VBS"

' Copy the executable package to the target PC
Set objFileCopy = objFSO.GetFile(strFile01)
objFileCopy.Copy(strDest01), True

' Copy the VBScript to the target PC
Set objFileCopy = objFSO.GetFile(strFile02)
objFileCopy.Copy(strDest02), True

' Variable to hold the construction of the SOON command
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strCmd = """\\SERVER\Share\SOON.EXE"" \\" & _
strWkstn & " 120 ""cscript C:\" & strVBS & """"

' Variable to hold the error return code of the SOON command
errReturn = objShell.Run(strCmd)

' Time stamp the spreadsheet
objSheet.Cells(a, 2).Value = Now

' Evaluate the error return code of the SOON command and write
' results to Excel spreadsheet
If errReturn = 0 Then
objSheet.Cells(a, 1).Value = strWkstn
objSheet.Cells(a, 4).Value = "Success"
Else
objSheet.Cells(a, 1).Value = strWkstn
objSheet.Cells(a, 4).Value = "Failure"
End If
Else
WScript.Echo vbTab & strWkstn & " unreachable on network."
objSheet.Cells(a, 1).Value = strWkstn
objSheet.Cells(a, 2).Value = Now
objSheet.Cells(a, 3).Value = "Unreachable on network."
objSheet.Cells(a, 4).Value = "Failure"
End If
Loop

' Increment the Excel row variable to move to the next row down
a = a + 1
Loop

' Close the text file
objTxtFile.Close
WScript.Echo "Deployment complete."
End Sub

Sub subVerifyInstall
WScript.Echo "Verifying execution..."

Dim strEvtMsg, strFailed, strStatus, strSource, strSuccess
Dim intEvtCode01, intEvtCode02

' Define the Source being looked for in the Application log
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strSource = "Utility"

' Define the Event IDs being looked for in the Application log
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
intEvtCode01 = 990 ' Success
intEvtCode02 = 991 ' Failure

' WQL query definition to look for any entries from a specific source with a
' specific event code
strFailed = "Select * From Win32_NTLogEvent Where Logfile = 'Application'" _
& " and SourceName = '" & strSource & "' and EventCode = " & intEvtCode02
strSuccess = "Select * From Win32_NTLogEvent Where Logfile = 'Application'" _
& " and SourceName = '" & strSource & "' and EventCode = " & intEvtCode01

' Set the Excel row variable to start on the second row
b = 2
Do While objSheet.Cells(b, 1).Value <> ""
strComputer = objSheet.Cells(b, 1).Value

' Ping the workstation, skipping it if it is unreachable on the network
strPing = "%comspec% /c ping -n 3 -w 1000 " & strComputer & ""
Set objExecObject = objShell.Exec(strPing)

Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadAll()

If InStr(strText, "Reply") > 0 Then
' Parse the application log based upon the value of the cell in the
' fourth column of the spreadsheet
Select Case objSheet.Cells(b, 4).Value
Case "Success"
WScript.Echo "Verifying execution on " & strComputer & "..."

On Error Resume Next
strStatus = getInstallStatus _
(strSuccess, strFailed, strComputer)

If strStatus = "F" Then
strEvtMsg = getEventLogMsg(strFailed, strComputer)
'objSheet.Cells(b, 5).Value = strEvtMsg
Else
strEvtMsg = getEventLogMsg(strSuccess, strComputer)
'objSheet.Cells(b, 5).Value = strEvtMsg
End If
objSheet.Cells(b, 5).Value = strEvtMsg
On Error Goto 0

Case Else
End Select
Else
WScript.Echo vbTab & strComputer & " unreachable on network."
End If
Loop

b = b + 1
Loop

WScript.Echo "Verification complete."
End Sub
' ==============================================================================
' END OF SCRIPT: deployEXE.VBS
' ==============================================================================

Script 2:

Code: Select all
' File Name:   runEXE.VBS
' Script Name:   runEXE.VBS
' Created:      2008.03.14
' Author:      Talen
' E-mail:
' ------------------------------------------------------------------------------
' ARGUMENTS :
'   None
' ------------------------------------------------------------------------------

' ------------------------------------------------------------------------------
' PURPOSE :
'   This script will run an executable on a workstation and create a custom entry
'   in the application log.
'   * NOTE: EVENTCREATE is a command line utility in Windows XP/Vista used to
'   create custom events in   the application log. See 'EVENTCREATE /?' for more
'   information. LOGEVENT is a command line utility found in the Windows 2000
'   Resource Kit and performs more or less the same function. See 'LOGEVENT /?'
'   for more information
' ------------------------------------------------------------------------------
'
' ------------------------------------------------------------------------------
' REVISION HISTORY :
' Date:
' Time:
' Issue:
' Solution:
'
' ------------------------------------------------------------------------------

' ==============================================================================
' SCRIPT BODY
' ==============================================================================
Option Explicit

Dim colItems, errReturn
Dim objFSO, objItem, objNet, objShell, objTxtFile, objWMI
Dim strCmd, strExe, strEvtFailure, strEvtSuccess, strOS, strRunEXEDebug
Dim strWkstn

Const ForWriting = 2

' Bind to the file system, network and shell objects
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objNet = CreateObject("WScript.Network")
Set objShell = CreateObject("WScript.Shell")

' Define the name of the debug output file
strRunEXEDebug = "C:\runEXEDebugOutput.TXT"

' Create the text file and close it
Set objTxtFile = objFSO.CreateTextFile(strRunEXEDebug)
objTxtFile.Close

' Open the text file for writing
Set objTxtFile = objFSO.OpenTextFile(strRunEXEDebug, ForWriting, True)

' Time stamp the debug file
objTxtFile.WriteLine(Now)

' Get the NetBIOS name of the workstation
strWkstn = objNet.ComputerName
objTxtFile.WriteLine("Workstation name: " & strWkstn)

' Define the executable and any parameters/arguments
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strExe = "Utility.EXE Parameters"

' Contruct the command to be run from the shell
strCmd = "C:\" & strExe
objTxtFile.WriteLine("Shell command: " & strCmd)

' Bind to the WMI service and query for the OS of the workstation
Set objWMI = GetObject("winmgmts:\\" & strWkstn & "\root\CIMV2")
Set colItems = objWMI.ExecQuery("SELECT * FROM Win32_OperatingSystem",,48)

' Set the strOS variable to the version number of the OS
For Each objItem in colItems
strOS = Left(objItem.Version, 3)
Next
objTxtFile.WriteLine("OS version number: " & strOS)

' Use the appropriate commands to create a custom application log entry based
' upon the installed OS (Vista is 6.0 and uses EVENTCREATE)
Select Case strOS
Case "5.0" ' Windows 2000
' Define the command to create a successful entry in the application log
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strEvtSuccess = "\\SERVER\Share\LOGEVENT.EXE -S I " & _
"-R Utility -E 990 -T 10000 ""Utility execution success."""

' Define the command to create a successful entry in the application log
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strEvtFailure = "\\SERVER\Share\LOGEVENT.EXE -S E " & _
"-R Utility -E 991 -T 10000 ""Utility execution failure."""

objTxtFile.WriteLine("OS version: Windows 2000")
Case "5.1" ' Windows XP
' Define the command to create a successful entry in the application log
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strEvtSuccess = "EVENTCREATE /T INFORMATION /SO Utility /ID 990 /L " & _
"APPLICATION /D ""Utility execution success."""

' Define the command to create an unsuccessful entry in the application
' log
' *** CHANGE TO SUIT NEEDS AS NECESSARY ***
strEvtFailure = "EVENTCREATE /T ERROR /SO Utility /ID 991 /L " & _
"APPLICATION /D ""Utility execution failure."""

objTxtFile.WriteLine("OS version: Windows XP")
End Select

' Execute the command and populate the errReturn variable with the result code
errReturn = objShell.Run(strCmd)
objTxtFile.WriteLine("errReturn: " & errReturn)

' Evaluate the result code and create the appropriate entry in the workstation
' application log
If errReturn = 0 Then
objTxtFile.WriteLine("Logging command: " & strEvtSuccess)
' Shell command to make success entry in application log.
objShell.Run strEvtSuccess
Else
objTxtFile.WriteLine("Logging command: " & strEvtFailure)
' Shell command to make failure entry in application log.
objShell.Run strEvtFailure
End If

objTxtFile.Close
' ==============================================================================
' END OF SCRIPT: deployEXE.VBS
' ==============================================================================

Just modify the scripts in the areas I’ve commented to get the script to work for you.

Leave a Reply

Your email address will not be published. Required fields are marked *

Advertise

If you'd like to advertise on The Mutt ( aka TheTAZZone.com ) feel free to contact us at: administration[at]thetazzone.com

TheTAZZone is a non-commercial entity. We do not sell any products or services ourselves. Our revenue comes from advertising and donations only.

We appreciate your support! Your advertising revenue ( or donations ) helps us to continue to upgrade, improve, and offset the costs of maintaining this site.

Donations can be made through the page ' Donate '.