Post by 1RealTruthThank you Richard. Your script looks really nice but I have a problem
with it. I'm not working on a domain. I'm trying to incorporate code
to do this in a VB program I'm writing. I have the process of ending
tasks down but I'm trying to incorporate batch files to shut down and
restart Cold Fusion and IIS. We have batch files to do this but not all
the servers have them.
I'm doing this in my spare time to try and help our NOC guys with their
job. Also I'm getting let go at the end of July. I wanted to do
something to help before I leave. It will also help me with getting
back into programming. I'm going to see if the company that bought us
will give me a good recommendation for my next job. My wife wants to go
back to Europe. She's a member of the EU but I'm not.
Any help will be greatly appreciated.
Thank you.
Here is a version of the program I linked that uses an array of computer
names, instead of a domain group. I have not tested the program, but this
should work even if there is no domain. In the code below I specify only one
computer in the array, but there could be as many as desired:
============
' Deploy.vbs
Option Explicit
Dim strExecutable, strGroup, m_strCommand
Dim m_objFSO, m_strProgram
Dim strScriptName, strScriptPath, strScriptFolder
Dim strComputer, strParms, strLogFile, strLocal
Dim m_objLogFile, m_objNetwork, m_objShell, m_strTempFile
Dim m_objLocal, m_strDrive, m_blnFirst, m_objSourceFile
Dim intSuccess, intFailure
Dim arrComputers
Const ForAppending = 8
' Specify array of computer NetBIOS names.
arrComputers = Array("MyComputer")
' Prompt for the program to run on each remote computer.
strExecutable = InputBox("Enter the full path and name of the program " _
& "to deploy to computers in the array", "Deployment Utility")
' Check for the existence of the file.
Set m_objFSO = CreateObject("Scripting.FileSystemObject")
If (m_objFSO.FileExists(strExecutable) = False) Then
Wscript.Echo "File " & strExecutable & " not found"
Wscript.Quit
End If
' Retrieve program name.
m_strProgram = m_objFSO.GetFileName(strExecutable)
' Prompt for command line parameters.
strParms = InputBox("Enter any command line parameters", _
"Deployment Utility")
strParms = Trim(strParms)
' Construct command to execute on remote computers.
m_strCommand = m_strProgram
If (strParms <> "") Then
m_strCommand = m_strCommand & " " & strParms
End If
' Retrieve temporary file name for ping operation.
Set m_objShell = CreateObject("Wscript.Shell")
m_strTempFile = m_objShell.ExpandEnvironmentStrings("%TEMP%")
m_strTempFile = m_strTempFile & "\RunResult.tmp"
' Determine current directory.
strScriptName = Wscript.ScriptName
strScriptPath = Wscript.ScriptFullName
strScriptFolder = Left(strScriptPath, _
Len(strScriptPath) - Len(strScriptName) - 1)
' Setup log file in current directory.
strLogFile = strScriptFolder & "\Deploy.log"
Set m_objLogFile = m_objFSO.OpenTextFile(strLogFile, ForAppending, True)
m_objLogFile.WriteLine "====="
m_objLogFile.WriteLine CStr(Now()) & " Deployment started"
m_objLogFile.WriteLine "-- Deployment executable " & strExecutable
m_objLogFile.WriteLine "-- Command to execute " & m_strCommand
m_objLogFile.WriteLine "-- Deploy to computers in array"
' Retrieve local computer name.
Set m_objNetwork = CreateObject("Wscript.Network")
strLocal = m_objNetwork.ComputerName
' Connect to local computer with WMI.
Set m_objLocal = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate,authenticationLevel=Pkt}!\\" _
& strLocal & "\root\cimv2")
m_objLogFile.WriteLine "-- Connected to local computer " & strLocal
' Default drive letter to map for copying executable file
' to remote computer.
m_strDrive = "Z:"
m_blnFirst = True
' Bind to local executable program file.
On Error Resume Next
Set m_objSourceFile = m_objLocal.Get("cim_datafile=""" _
& Replace(strExecutable, "\", "\\") & """")
If (Err.Number <> 0) Then
On Error GoTo 0
m_objLogFile.WriteLine "-- ### File not found: " & strExecutable
Wscript.Echo "File not found: " & strExecutable
Wscript.Quit
End If
On Error GoTo 0
' Enumerate array of computer names.
intSuccess = 0
intFailure = 0
For Each strComputer In arrComputers
m_objLogFile.WriteLine CStr(Now()) _
& " deploy to computer " & strComputer
Wscript.Echo "Deploying to " & strComputer
If (IsConnectible(strComputer, 1, 500) = True) Then
m_objLogFile.WriteLine "-- Computer found"
If (RunProgram(strComputer) = True) Then
intSuccess = intSuccess + 1
Wscript.Echo "-- success"
Else
intFailure = intFailure + 1
Wscript.Echo "-- failure"
End If
Else
m_objLogFile.WriteLine "-- ### computer not available"
intFailure = intFailure + 1
Wscript.Echo "-- not available"
End If
Next
' Log results.
m_objLogFile.WriteLine CStr(Now()) & " Deployment finished"
m_objLogFile.WriteLine "-- Successfully deployed to " & CStr(intSuccess) _
& " computers"
m_objLogFile.WriteLine "-- Failed to deploy to " & CStr(intFailure) _
& " computers"
m_objLogFile.WriteLine "====="
m_objLogFile.Close
' Notify user.
Wscript.Echo "Deployment finished. See log " & strLogFile
Function IsConnectible(ByVal strHost, ByVal intPings, ByVal intTO)
' Returns True if strHost can be pinged.
' Based on a program by Alex Angelopoulos and Torgeir Bakken.
' Requires the following variables be declared with global scope:
' m_objShell, m_strTempFile, m_objFSO.
Dim objFile, strResults
If (intPings = "") Then
intPings = 2
End If
If (intTO = "") Then
intTO = 750
End If
Const OpenAsDefault = -2
Const FailIfNotExist = 0
Const ForReading = 1
' Ping the host and redirect output to temporary file.
m_objShell.Run "%comspec% /c ping -n " & intPings & " -w " & intTO _
& " " & strHost & ">" & m_strTempFile, 0, True
' Read the temporary file.
Set objFile = m_objFSO.OpenTextFile(m_strTempFile, ForReading, _
FailIfNotExist, OpenAsDefault)
strResults = objFile.ReadAll
objFile.Close
' Determine if the host responded.
If (InStr(strResults, "TTL=") <> 0) Then
IsConnectible = True
Else
IsConnectible = False
End If
End Function
Function RunProgram(ByVal strComputer)
' Function to run a program on a remote computer.
' Returns True if successful, False otherwise.
' Requires the following variables be declared with global scope:
' m_objLogFile, m_strProgram, m_objNetwork, m_blnFirst,
' m_strDrive, m_objSourceFile, m_strCommand, m_objLocal.
Dim objRemote, objProcess, intReturnCode, objDestFile
Dim intWaitTime, blnDelete, objRemoteProcess, colProcesses
' Connect to remote computer with WMI.
On Error Resume Next
Set objRemote = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate,authenticationLevel=Pkt}!\\" _
& strComputer & "\root\cimv2")
If (Err.Number <> 0) Then
m_objLogFile.WriteLine _
"-- ### Failed to connect with WMI, Error Number: " _
& Err.Number & ", Description: " & Err.Description
On Error GoTo 0
RunProgram = False
Exit Function
End If
On Error GoTo 0
m_objLogFile.WriteLine "-- Connected with WMI"
' Check if executable running on remote computer.
Set colProcesses = objRemote.ExecQuery _
("SELECT * FROM Win32_Process " _
& "WHERE Name = '" & m_strProgram & "'")
For Each objRemoteProcess In colProcesses
m_objLogFile.WriteLine _
"-- ### Program already running, no deployment"
RunProgram = False
Exit Function
Next
' Map a drive to the root of the C: drive on remote computer.
On Error Resume Next
m_objNetwork.MapNetworkDrive m_strDrive, "\\" & strComputer & "\C$"
If (Err.Number <> 0) Then
On Error GoTo 0
' Drive mapping failed. If this is the first computer,
' try another drive letter.
If (m_blnFirst = True) Then
m_blnFirst = False
m_strDrive = "Y:"
On Error Resume Next
m_objNetwork.MapNetworkDrive m_strDrive, "\\" _
& strComputer & "\C$"
If (Err.Number <> 0) Then
On Error GoTo 0
' Try another drive letter.
m_strDrive = "X:"
On Error Resume Next
m_objNetwork.MapNetworkDrive m_strDrive, "\\" _
& strComputer & "\C$"
If (Err.Number <> 0) Then
On Error GoTo 0
m_objLogFile.WriteLine "-- ### Unable to map any drive"
RunProgram = False
Exit Function
End If
End If
Else
m_objLogFile.WriteLine "-- ### Unable to map drive " _
& m_strDrive
RunProgram = False
Exit Function
End If
End If
On Error GoTo 0
m_blnFirst = False
m_objLogFile.WriteLine "-- Drive mapped"
' Copy the executable from the local computer to the remote computer.
intReturnCode = m_objSourceFile.Copy(m_strDrive & "\\" & m_strProgram)
If (intReturnCode <> 0) And (intReturnCode <> 10) Then
' Failure detected and failure was not "file aleady exists".
m_objLogFile.WriteLine _
"-- ### Failed to copy executable file, Error: " _
& CStr(intReturnCode)
RunProgram = False
' Remove drive mapping.
m_objNetwork.RemoveNetworkDrive m_strDrive, True
m_objLogFile.WriteLine "-- Drive mapping removed"
Exit Function
End If
m_objLogFile.WriteLine "-- Executable file copied"
' Execute the program on the remote computer.
Set objProcess = objRemote.Get("Win32_Process")
' Run the program in silent mode.
intReturnCode = objProcess.Create("c:\\" & m_strCommand)
If (intReturnCode <> 0) Then
m_objLogFile.WriteLine "-- ### Failed to start program, Error: " _
& CStr(intReturnCode)
RunProgram = False
' Remove drive mapping.
m_objNetwork.RemoveNetworkDrive m_strDrive, True
m_objLogFile.WriteLine "-- Drive mapping removed"
Exit Function
End If
m_objLogFile.WriteLine "-- Program started at " & CStr(Now())
' Get reference to the file that was copied.
Set objDestFile = m_objLocal.Get("cim_datafile=""" _
& m_strDrive & "\\" & m_strProgram & """")
' Attempt to delete the file once per second for 2 minutes.
' The file cannot be deleted until the program stops running.
blnDelete = False
Wscript.Sleep 1000
For intWaitTime = 0 To 120
' Pause 1 second
Wscript.Sleep 1000
' Check if file can be deleted.
If (objDestFile.Delete() = 0) Then
blnDelete = True
Exit For
End If
Next
m_objLogFile.WriteLine "-- Deployment successful at " & CStr(Now())
If (blnDelete = False) Then
m_objLogFile.WriteLine "-- ### Caution: Unable to delete executable"
End If
' Remove drive mapping.
m_objNetwork.RemoveNetworkDrive m_strDrive, True
m_objLogFile.WriteLine "-- Drive mapping removed"
RunProgram = True
End Function
==========
If this is a VB program, perhaps you don't want to query for things like the
file to be deployed and command line parameters, but you should be able to
assign appropriate values in place of the prompts. If there is never more
than one computer, you could revise the program to work with one value of
strComputer rather than an array. For example, a version with everything
hard coded (you might take values from a form) follows. I don't include the
functions as they are unchanged. Since you also may not want anything
echoed, I've removered the Wscript.Echo statements and replaced with MsgBox
statements (or you might eliminate them all). I also replaced Wscript.Quit
with End. However, note the problem I mention after this code:
==============
' Deploy.vbs
Option Explicit
Dim strExecutable, strGroup, m_strCommand
Dim m_objFSO, m_strProgram
Dim strScriptName, strScriptPath, strScriptFolder
Dim strComputer, strParms, strLogFile, strLocal
Dim m_objLogFile, m_objNetwork, m_objShell, m_strTempFile
Dim m_objLocal, m_strDrive, m_blnFirst, m_objSourceFile
Dim intSuccess, intFailure
Const ForAppending = 8
' Specify computer NetBIOS name.
strComputer = "MyComputer"
' Specify the program to run on each remote computer.
strExecutable = "F:\MyFolder\MyUtility.exe"
' Check for the existence of the file.
Set m_objFSO = CreateObject("Scripting.FileSystemObject")
If (m_objFSO.FileExists(strExecutable) = False) Then
Call MsgBox("File " & strExecutable & " not found")
End
End If
' Retrieve program name.
m_strProgram = m_objFSO.GetFileName(strExecutable)
' Specify any command line parameters.
strParms = ""
' Construct command to execute on remote computers.
m_strCommand = m_strProgram
If (strParms <> "") Then
m_strCommand = m_strCommand & " " & strParms
End If
' Retrieve temporary file name for ping operation.
Set m_objShell = CreateObject("Wscript.Shell")
m_strTempFile = m_objShell.ExpandEnvironmentStrings("%TEMP%")
m_strTempFile = m_strTempFile & "\RunResult.tmp"
' Determine current directory.
strScriptName = Wscript.ScriptName
strScriptPath = Wscript.ScriptFullName
strScriptFolder = Left(strScriptPath, _
Len(strScriptPath) - Len(strScriptName) - 1)
' Setup log file in current directory.
strLogFile = strScriptFolder & "\Deploy.log"
Set m_objLogFile = m_objFSO.OpenTextFile(strLogFile, ForAppending, True)
m_objLogFile.WriteLine "====="
m_objLogFile.WriteLine CStr(Now()) & " Deployment started"
m_objLogFile.WriteLine "-- Deployment executable " & strExecutable
m_objLogFile.WriteLine "-- Command to execute " & m_strCommand
m_objLogFile.WriteLine "-- Deploy to computer " & strComputer
' Retrieve local computer name.
Set m_objNetwork = CreateObject("Wscript.Network")
strLocal = m_objNetwork.ComputerName
' Connect to local computer with WMI.
Set m_objLocal = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate,authenticationLevel=Pkt}!\\" _
& strLocal & "\root\cimv2")
m_objLogFile.WriteLine "-- Connected to local computer " & strLocal
' Default drive letter to map for copying executable file
' to remote computer.
m_strDrive = "Z:"
m_blnFirst = True
' Bind to local executable program file.
On Error Resume Next
Set m_objSourceFile = m_objLocal.Get("cim_datafile=""" _
& Replace(strExecutable, "\", "\\") & """")
If (Err.Number <> 0) Then
On Error GoTo 0
m_objLogFile.WriteLine "-- ### File not found: " & strExecutable
Call MsgBox("File not found: " & strExecutable)
End
End If
On Error GoTo 0
intSuccess = 0
intFailure = 0
m_objLogFile.WriteLine CStr(Now()) _
& " deploy to computer " & strComputer
If (IsConnectible(strComputer, 1, 500) = True) Then
m_objLogFile.WriteLine "-- Computer found"
If (RunProgram(strComputer) = True) Then
intSuccess = intSuccess + 1
Else
intFailure = intFailure + 1
End If
Else
m_objLogFile.WriteLine "-- ### computer not available"
intFailure = intFailure + 1
End If
' Log results.
m_objLogFile.WriteLine CStr(Now()) & " Deployment finished"
m_objLogFile.WriteLine "-- Successfully deployed to " & CStr(intSuccess) _
& " computers"
m_objLogFile.WriteLine "-- Failed to deploy to " & CStr(intFailure) _
& " computers"
m_objLogFile.WriteLine "====="
m_objLogFile.Close
=========
A problem in VB is that the Wscript.Sleep command used in Function
RunProgram is not supported in VB. You would need to remove the two Sleep
statements, but I suspect the lack of a delay will cause problems. You may
need to use a timer control instead. Note you may also want to save the log
file somewhere else (the above saves in the folder where the script
resides). Or you may skip the log file feature.
--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--