VBS shell.run breaking - vbscript

My minecraft server tends to crash fairly often so I wrote a script that checks my minecraft server, if its up it does nothing, if it is down it executes this code:
Set oShell= CreateObject("WScript.Shell")
strProcess = "cmd.exe"
oShell.Run "TaskKill /im " & strProcess & " /f /t", , True
WScript.sleep 1000
oShell.Run "c:\minecraft_launch.bat"
Set oShell = Nothing
Basically I kill any currently running server (cmd since it is being run from a batch file) then I start it back up. This check is run every 5mins via task scheduler.
This is the contents of the batch file:
#echo off
"C:\Program Files\Java\jre6\bin\java.exe" -Xmx1024M -Xms1024M -jar "%appdata%\- minecraft_server\minecraft_server.jar" >> "%appdata%\- minecraft_server\s.log"
When I run it, it works. Everytime, but.....When it runs automatically, it stops working. I don't know how many times it will work until it quits. What happens is I notice it is down, so I check my computer. No server running, no process running, no javaw.exe or cmd.exe running. Nothing, but when I try to start the server it won't start. I have to reboot the whole machine to get the server to start. I think I am missing something stupid simple here. Any ideas?

The problem could be that the timeout is too short so you try to start it while it's still being closed. In any way, vbscript itself can check and terminate processes with more controll. See http://www.activexperts.com/activmonitor/windowsmanagement/adminscripts/processes/ for short scripts that monitor and stop processes.
Here a script from Rob Van der woude which usually are reliable, this monitors outlook.exe so i guess you would be monitoring javaw.exe
KillProc "outlook.exe"
Sub KillProc( myProcess )
'Authors: Denis St-Pierre and Rob van der Woude
'Purpose: Kills a process and waits until it is truly dead
Dim blnRunning, colProcesses, objProcess
blnRunning = False
Set colProcesses = GetObject( _
"winmgmts:{impersonationLevel=impersonate}" _
).ExecQuery( "Select * From Win32_Process", , 48 )
For Each objProcess in colProcesses
If LCase( myProcess ) = LCase( objProcess.Name ) Then
' Confirm that the process was actually running
blnRunning = True
' Get exact case for the actual process name
myProcess = objProcess.Name
' Kill all instances of the process
objProcess.Terminate()
End If
Next
If blnRunning Then
' Wait and make sure the process is terminated.
' Routine written by Denis St-Pierre.
Do Until Not blnRunning
Set colProcesses = GetObject( _
"winmgmts:{impersonationLevel=impersonate}" _
).ExecQuery( "Select * From Win32_Process Where Name = '" _
& myProcess & "'" )
WScript.Sleep 100 'Wait for 100 MilliSeconds
If colProcesses.Count = 0 Then 'If no more processes are running, exit loop
blnRunning = False
End If
Loop
' Display a message
WScript.Echo myProcess & " was terminated"
Else
WScript.Echo "Process """ & myProcess & """ not found"
End If
End Sub

Related

How can I redirect my vbscript output to a file using batch file?

I am new to Windows Scripting. I have a simple script for archiving using WinRAR CLI utility. I have to schedule this script using batch file. During archiving there are some errors and I want them to write in a simple text file or at least I can write entire output of archiving in a file. How can I change my code to do this?
Dim MyDate
Dim OutputFile
const WaitUntilFinished = true, DontWaitUntilFinished = false, ShowWindow = 1, DontShowWindow = 0
MyDate = Replace(Date, "/", "-")
OutputFile = "backup-" & mydate & ".rar"
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.CurrentDirectory = "C:\Users\ABC\Desktop\"
objShell.Run "C:\windows\Rar.exe a .\VBScripts\backups\" & OutputFile & " software", ShowWindow, WaitUntilFinished
objShell.Popup "Archiving Completed Successfully!",5, "Scheduled Backup"
Set objShell = Nothing
Batch file is like this;
#echo off
start /wait C:\Users\ABC\Desktop\VBScripts\scheduled_backup.vbs
Change your command line to include redirection to a log file:
logfile = "C:\path\to\your.log"
objShell.Run "%COMSPEC% /c C:\windows\Rar.exe a .\VBScripts\backups\" & _
OutputFile & " software >""" & logfile & """", ShowWindow, WaitUntilFinished
Use this function instead of WScript.Shell.Run:
' Runs an external program and pipes it's output to
' the StdOut and StdErr streams of the current script.
' Returns the exit code of the external program.
Function Run (ByVal cmd)
Dim sh: Set sh = CreateObject("WScript.Shell")
Dim wsx: Set wsx = Sh.Exec(cmd)
If wsx.ProcessID = 0 And wsx.Status = 1 Then
' (The Win98 version of VBScript does not detect WshShell.Exec errors)
Err.Raise vbObjectError,,"WshShell.Exec failed."
End If
Do
Dim Status: Status = wsx.Status
WScript.StdOut.Write wsx.StdOut.ReadAll()
WScript.StdErr.Write wsx.StdErr.ReadAll()
If Status <> 0 Then Exit Do
WScript.Sleep 10
Loop
Run = wsx.ExitCode
End Function
Call script instead of start in your batch and use redirection:
script //nologo C:\Users\ABC\Desktop\VBScripts\scheduled_backup.vbs 2> errors.txt

How can I call a function in a vbscript with command line arguments?

I have a script that executes remotely to see if a program is running. It works fine but I need it to check for several programs on several servers and I don't want to re-write it. I'm trying to see if I can call the function within the vbscript via command line so that I can use 1 script and change the arguments at the command line.
Function IsProcessRunning(strComputer, strProcess)
Dim Process, strObject
IsProcessRunning = 0
strObject = "winmgmts://" & strComputer
For Each Process in GetObject( strObject ).InstancesOf( "win32_process" )
If UCase( Process.name ) = UCase( strProcess ) Then
IsProcessRunning = 1
If IsProcessRunning = 1 Then
WScript.echo 1 & ": " & strProcess & " is currently running on " & strComputer
End If
Exit Function
End If
Next
WScript.echo 0 & ": " & strProcess " is NOT running on " & strComputer
End Function
What I'm hoping for is to be able to run this via cmd like:
run.vbs IsprocessRunning Server3 Program2.exe
UPDATE
Why not to use WMIC? E. g. type in command line:
wmic /node:server1 process where name='explorer.exe' get processid
to get all launched explorers process ID on server1.
SOURCE
Use WScript.Arguments property:
IsProcessRunning WScript.Arguments(0), WScript.Arguments(1)
Function IsProcessRunning(strComputer, strProcess)
Dim Process, strObject
IsProcessRunning = 0
strObject = "winmgmts://" & strComputer
For Each Process in GetObject( strObject ).InstancesOf( "win32_process" )
If UCase(Process.name) = UCase(strProcess) Then
IsProcessRunning = 1
WScript.echo 1 & ": " & strProcess & " is currently running on " & strComputer
Exit Function
End If
Next
WScript.echo 0 & ": " & strProcess & " is NOT running on " & strComputer
End Function
Better to add some check if the appropriate command line arguments provided to script.

capture command line output in vbscript

Got a simple script that executes a command to a server - briefly:
//Create shell
set WshShell=CreateObject("WScript.Shell")
WshShell.run "cmd.exe"
//send commands
WshShell.SendKeys "telnet IP_ADDRESS"
WshShell.Sendkeys "dir"
Server offers feedback which I want to capture. I just need to capture the first line into a variable, and then just print that variable out to confirm.
Can you help? Thanks.
Do not use the Windows telnet client for automation purposes. The telnet client that ships with Windows was made for interactive use only.
I'd use plink (from the PuTTY suite) in batch mode for this:
plink.exe -telnet -batch IP_ADDRESS dir
The tool doesn't require installation, so you can simply deploy it alongside your script.
Run it either in a batch file using head/tail, or in a VBScript using the Exec method, so you can read from StdOut:
addr = "62.39.x.x"
port = 24
timeout = 300 'seconds
timedOut = False
cmdline = "echo ""mute near get"" | plink.exe -telnet -batch " & addr & " -P " & port
Set sh = CreateObject("WScript.Shell")
'change working directory to directory containing script and plink executable
Set fso = CreateObject("Scripting.FileSystemObject")
sh.CurrentDirectory = fso.GetParentFolderName(WScript.ScriptFullName)
'wait until command completes or timeout expires
expiration = DateAdd("s", timeout, Now)
Set cmd = sh.Exec("%COMSPEC% /c " & cmdline)
Do While cmd.Status = 0 And Now < expiration
WScript.Sleep 100
Loop
If cmd.Status = 0 Then
cmd.Terminate
timedOut = True
End If
WScript.Echo cmd.StdOut.ReadAll
If cmd.ExitCode <> 0 Then
WScript.Echo "Command terminated with exit code " & cmd.ExitCode & "."
WScript.Echo cmd.StdErr.ReadAll
WScript.Quit 1
ElseIf timedOut Then
WScript.Echo "Command timed out."
WScript.Echo cmd.StdErr.ReadAll
WScript.Quit 2
End If
It might not be the best method, but worked for me:
Windows telnet command can save the output in client side using -f arguments. Therefore, you could use:
WshShell.SendKeys "telnet -f D:\output\telnet.out IP_ADDRESS"
and at the end of your script, simply process the content of telnet.out

Permission elevation from VBScript

We run Dynamics GP. Because of the way it stores forms/reports, I need to have some install scripts that copy a .SET file into the program directory. This can be done manually, but it's much quicker to just have a user run an installer script which installs the proper files for them.
I've been building a VBScript installer that copies the necessary files around. The tricky part is that some clients are running Windows XP, and some are running Windows 7 (or even 8). UAC is enabled, so permissions come into play.
The way I've tried to do it is by blindly attempting to copy the files, and if a permission error is detected, it relaunches the script with administrator permissions. Where we've run into problems is some (all?) Windows 7 machines have virtualized file/registry writes enabled, so when the script tries to copy files into C:\Program Files\Microsoft Dynamics\GP2010, it silently fails and copies them to the user's AppData\Local\VirtualStore directory. This doesn't work properly with GP.
So what I need to do is have the script copy the files to C:\Program Files (not the VirtualStore directory), and elevate permissions only if necessary. If I have it elevate across the board, this causes the Windows XP machines to simply pop up a cryptic "Run As" dialog box when launching the script.
Here's what I have so far:
Dim WSHShell, FSO, Desktop, DesktopPath
Set FSO = CreateObject("Scripting.FileSystemObject")
Set WSHShell = CreateObject("WScript.Shell")
Desktop = WSHShell.SpecialFolders("Desktop")
DesktopPath = FSO.GetAbsolutePathName(Desktop)
'Set working directory to directory the script is in.
'This ends up being C:\Windows\System32 if the script is
'started from ShellExecute, or a link in an email, thus breaking
'relative paths.
WSHShell.CurrentDirectory = FSO.GetFile(WScript.ScriptFullName).ParentFolder
On Error Resume Next
If FSO.FolderExists("C:\Program Files (x86)") Then
WScript.Echo "Installing 64-bit."
FSO.CopyFile "64-bit\*.set", "C:\Program Files (x86)\Microsoft Dynamics\GP2010\", True
FSO.CopyFile "64-bit\*.lnk", DesktopPath, True
ElseIf FSO.FolderExists("C:\Program Files\Microsoft Dynamics\GP2010\Mekorma MICR") Then
WScript.Echo "Installing 32-bit (with MICR)."
FSO.CopyFile "32-bit MICR\*.set", "C:\Program Files\Microsoft Dynamics\GP2010\", True
FSO.CopyFile "32-bit MICR\*.lnk", DesktopPath, True
Else
WScript.Echo "Installing 32-bit."
FSO.CopyFile "32-bit\*.SET", "C:\Program Files\Microsoft Dynamics\GP2010\", True
FSO.CopyFile "32-bit\*.lnk", DesktopPath, True
End If
If Err.Number = 70 Then
CreateObject("Shell.Application").ShellExecute "wscript.exe", """" & WScript.ScriptFullName & """" , "", "runas", 1
WScript.Quit
ElseIf Err.Number <> 0 Then
MsgBox "Error " & Err.Number & vbCrLf & Err.Source & vbCrLf & Err.Description
Else
MsgBox "Installed successfully."
End If
In summary: How do I have a VBScript elevate permissions without causing XP to stall at a "Run As" dialog box, and without causing Windows 7 to copy the files to AppData\Local\VirtualStore instead?
Improved on #db2 answer:
real elevation testing, without depending on passed arguments
passes all original arguments to the elevated script
uses the same host of the initial script: wscript.exe, cscript.exe, whatever
Code:
Set OSList = GetObject("winmgmts:").InstancesOf("Win32_OperatingSystem")
For Each OS In OSList
If InStr(1, OS.Caption, "XP") = 0 And InStr(1, OS.Caption, "Server 2003") = 0 Then
With CreateObject("WScript.Shell")
IsElevated = .Run("cmd.exe /c ""whoami /groups|findstr S-1-16-12288""", 0, true) = 0
If Not IsElevated Then
Dim AllArgs
For Each Arg In WScript.Arguments
If InStr( Arg, " " ) Then Arg = """" & Arg & """"
AllArgs = AllArgs & " " & Arg
Next
Command = """" & WScript.ScriptFullName & """" & AllArgs
With CreateObject("Shell.Application")
.ShellExecute WScript.FullName, " //nologo " & Command, "", "runas", 1
WScript.Echo WScript.FullName & " //nologo " & Command
End With
WScript.Quit
End If
End With
End If
Next
' Place code to run elevated here
Seems like this is the simplest way to do it.
Check OS version.
If it's not XP or 2003 (I don't anticipate this running on anything older), re-execute with elevation.
Here's the code block I added to the beginning of the script:
Dim OSList, OS, UAC
UAC = False
If WScript.Arguments.Count >= 1 Then
If WScript.Arguments.Item(0) = "elevated" Then UAC = True
End If
If Not(UAC) Then
Set OSList = GetObject("winmgmts:").InstancesOf("Win32_OperatingSystem")
For Each OS In OSList
If InStr(1, OS.Caption, "XP") = 0 And InStr(1, OS.Caption, "Server 2003") = 0 Then
CreateObject("Shell.Application").ShellExecute "wscript.exe", """" & WScript.ScriptFullName & """ elevated" , "", "runas", 1
WScript.Quit
End If
Next
End If

Ping script with loop and save in a txt

i try to make an Ping script with vbs. I need a Script, that ping (no ping limit, the program will run all the time) a computername in the network every 2 seconds and save the results in a txt file.
For Example:
06/08/2010 - 13:53:22 | The Computer "..." is online
06/08/2010 - 13:53:24 | The Computer "..." is offline
Now i try a little bit:
strComputer = "TestPC"
Set objPing = GetObject("winmgmts:{impersonationLevel=impersonate}")._
ExecQuery("select * from Win32_PingStatus where address = '"_
& strComputer & "'")
For Each objStatus in objPing
If IsNull(objStatus.StatusCode) Or objStatus.StatusCode <> 0 Then
..........
Next
And than i don't know how to make it. (I'm new with vbs :-))
I hope some one can help me.
Greeting,
matthias
Try this
Option Explicit
Dim strHost, strFile
strHost = "www.google.com" '"127.0.0.1"
strFile = "C:\Test.txt"
PingForever strHost, strFile
Sub PingForever(strHost, outputfile)
Dim Output, Shell, strCommand, ReturnCode
Set Output = CreateObject("Scripting.FileSystemObject").OpenTextFile(outputfile, 8, True)
Set Shell = CreateObject("wscript.shell")
strCommand = "ping -n 1 -w 300 " & strHost
While(True)
ReturnCode = Shell.Run(strCommand, 0, True)
If ReturnCode = 0 Then
Output.WriteLine Date() & " - " & Time & " | The Computer " & strHost & " is online"
Else
Output.WriteLine Date() & " - " & Time & " | The Computer " & strHost & " is offline"
End If
Wscript.Sleep 2000
Wend
End Sub
You put your pings inside a loop of some kind and then use Wscript.Sleep 2000 to sleep for 2 seconds.
Then you use the File System Object (FSO) to write to a file. Information can be found here.
Edit: Something like this might work:
Const OpenFileForAppending = 8
Dim fso, ts
Set fso = CreateObject("Scripting. FileSystemObject")
While 1 > 0 ' loop forever
Set ts = fso.OpenTextFile("c:\temp\test.txt", OpenFileForAppending, True)
' do your pinging code
'if ok
ts.WriteLine("OK")
'else
ts.WriteLine("Not OK")
'endif
ts.Close()
Wscript.Sleep 2000
Wend

Resources