Home All Groups Group Topic Archive Search About

Execute a batch file on remote host

Author
30 Oct 2007 4:16 PM
Hulicat
Running Windows 2003 R2 I need to execute a batch on remote Windows
2003 R2 machine.

I have tried a number of things including rexec, etc.

The goal would not to deploy any additional code to the remote host.

Is there a way to this via Cscript?do I need to write a vbs script?

Thanks,
Dennis

Author
30 Oct 2007 4:52 PM
Chris M
Hulicat wrote:
> Running Windows 2003 R2 I need to execute a batch on remote Windows
> 2003 R2 machine.
>
> I have tried a number of things including rexec, etc.
>
> The goal would not to deploy any additional code to the remote host.
>
> Is there a way to this via Cscript?do I need to write a vbs script?

Check out PsExec:

http://www.microsoft.com/technet/sysinternals/Security/PsExec.mspx

--
Chris M.
Author
30 Oct 2007 6:04 PM
Richard Mueller [MVP]
Dennis wrote:

> Running Windows 2003 R2 I need to execute a batch on remote Windows
> 2003 R2 machine.
>
> I have tried a number of things including rexec, etc.
>
> The goal would not to deploy any additional code to the remote host.
>
> Is there a way to this via Cscript?do I need to write a vbs script?

A VBScript program can use WMI to connect to the remote computer, copy the
executable (a batch file in this case), run it, wait for execution to
complete, then delete the file. I have an example VBScript program that does
this for all computers in a domain group. You can either modify this for one
computer, or place the computer object in a group by itself. The program
deploys only to computers in the group, so it does not hurt to have user
objects in the group.

http://www.rlmueller.net/Deploy.htm

The program writes a log to document everything.

--
Richard Mueller
Microsoft MVP Scripting and ADSI
Hilltop Lab - http://www.rlmueller.net
--
Author
19 Jun 2009 3:34 AM
1RealTruth
Thank 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.

'Richard Mueller [MVP Wrote: > ;3272402']Dennis wrote:
Show quoteHide quote
>
> > Running Windows 2003 R2 I need to execute a batch on remote Windows
> > 2003 R2 machine.
> >
> > I have tried a number of things including rexec, etc.
> >
> > The goal would not to deploy any additional code to the remote host.
> >
> > Is there a way to this via Cscript?do I need to write a vbs script?
>
> A VBScript program can use WMI to connect to the remote computer, copy > the
> executable (a batch file in this case), run it, wait for execution to
> complete, then delete the file. I have an example VBScript program that > does
> this for all computers in a domain group. You can either modify this > for one
> computer, or place the computer object in a group by itself. The > program
> deploys only to computers in the group, so it does not hurt to have > user
> objects in the group.
>
> http://www.rlmueller.net/Deploy.htm
>
> The program writes a log to document everything.
>
> --
> Richard Mueller
> Microsoft MVP Scripting and ADSI
> Hilltop Lab - http://www.rlmueller.net
> -- -- 1RealTruth ------------------------------------------------------------------------ 1RealTruth's Profile: http://forums.techarena.in/members/106922.htm View this thread: http://forums.techarena.in/server-scripting/843476.htmhttp://forums.techarena.in
Author
19 Jun 2009 6:31 PM
Richard Mueller [MVP]
Show quote Hide quote
"1RealTruth" <1RealTruth.3u0frb@DoNotSpam.com> wrote in message
news:1RealTruth.3u0frb@DoNotSpam.com...
>
> Thank 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
--
Author
19 Jun 2009 8:05 PM
1RealTruth
Thank you.  I'll test it out tonight when I get home from work.

I was checking out more of your website last night.  You have a lot of really nice programs.

Thanks again,
Kevin -- 1RealTruth ------------------------------------------------------------------------ 1RealTruth's Profile: http://forums.techarena.in/members/106922.htm View this thread: http://forums.techarena.in/server-scripting/843476.htmhttp://forums.techarena.in
Author
30 Oct 2007 8:36 PM
urkec
Show quote Hide quote
"Hulicat" wrote:

> Running Windows 2003 R2 I need to execute a batch on remote Windows
> 2003 R2 machine.
>
> I have tried a number of things including rexec, etc.
>
> The goal would not to deploy any additional code to the remote host.
>
> Is there a way to this via Cscript?do I need to write a vbs script?
>
> Thanks,
> Dennis
>
>

You can try to modify this sample from the Script Center.
http://www.microsoft.com/technet/scriptcenter/scripts/os/process/procthd/pcthvb03.mspx

I think you can't run interactive processes using Win32_Process class on
Windows 2003, but I'm not sure.

--
urkec