VBscript Unable to Run Shell Command - vbscript

I have set up the following Sub to run shell commands quickly and easily.
This script works for the login scripts at my company without fail.
I am currently developing a script to add a large batch of users to our domain.
When I used this Sub in my new script I receive an error saying that the file cannot be found.
I have tried using the fix in this stackoverflow post, but I recieve the same error even with this code.
VBScript WScript.Shell Run() - The system cannot find the file specified
The part I find puzzling is that this sub works just fine when run from the netlogon folder of our domain controller.
What am I doing wrong?
Thanks,
Sub runcommand(strCommand)
Dim objWshShell, intRC
set objWshShell = WScript.CreateObject("WScript.Shell")
intRC = objWshShell.Run(strCommand, 0, TRUE)
call reportError(intRC,strCommand)
set objWshShell = nothing
end Sub
function reportError(intRC, command)
if intRC <> 0 then
WScript.Echo "Error Code: " & intRC
WScript.Echo "Command: " & command
end if
end function

The previous values for strCommand had no spaces and were very straightforward. Your new script is passing more complex variables to your Sub so you need additional conditional handling, as Alex K. pointed out in his Collusion (i.e., "Comment/Solution") above. Alex K.'s sample above is perfect, so, being a Point Pimp tonight, will post it as the solution:
objWshShell.Run("cmd /k echo Hello World", 1, TRUE)

Related

Executing for loop to call Windows application

I have an existing VBScript which calls an application, then loops if the application exits via user intervention, if a certain user is logged in, otherwise it runs Explorer:
' Declare variables
dim fso
dim shell
dim oWshNet
set shell = CreateObject("WScript.Shell")
' get name of user logging in
set oWshNet = Wscript.CreateObject("Wscript.Network")
sUser = oWshNet.Username
' Run Aplication if user is user1
if oWshnet.Username = "user1" Then
do
shell.exec "C:\Program Files\Canon\MP Navigator EX 4.0\mpnex40.exe",0,true
loop
Else
shell.run "C:\windows\system32\explorer.exe"
end if
I have changed to a new application and now find that it will only run the application using shell.exec. shell.run causes a path not found error. Using shell.exec without the loop would not normally be a problem but as I require a loop which constantly rechecks for the exit of the application, I can't seem to use shell.exec with the ,0,true parameter.
Any ideas how I can get round this?
Stick with the Run method. Exec doesn't support additional arguments, and particularly doesn't support waiting for the executed program to return.
The reason why you got the "path not found" error is because your path contains spaces. You need to put double quotes around the path (inside the double quoted string) so that the whole path is recognized as one single token instead of multiple tokens C:\Program, Files\Canon\MP, aso.
Nested double quotes can be added for instance like this (doubling the double quotes escapes them inside a string):
shell.Run """C:\Program Files\Canon\MP Navigator EX 4.0\mpnex40.exe""", 0, True
or by using a quoting function (which is the more versatile approach):
Function qq(str) : qq = """" & str & """" : End Function
...
shell.Run qq("C:\Program Files\Canon\MP Navigator EX 4.0\mpnex40.exe"), 0, True

wshShell.Exec Error 80070002 "The system cannot find the file specified"

I'm trying to use either wshShell.Exec or wshShell.Run to run a script through another script. I have tried both methods, and both methods give me the same error. I've Googled the issue and can't find anything that seems to fix the issue. The only suggestion that really was very relevant was to try using wshShell.Run instead of Exec.
Here's the relevant part of my script:
strScriptPath = "T:\IT resources\Scripts\Shutdown Scripts"
strForceShutdown = "ForceShutdown.vbs"
For j = 0 to 99
Set objActive = wshShell.Run(strForceShutdown)
' In case I ever need to get this working to run it from another folder.
' Set objActive = wshShell.Exec("cd " & strScriptPath & "")
' Set objActive = wshShell.Exec("wscript " & strForceShutdown & "")
constConf = MsgBox("Automatic shutdown initializing. Continue?" & chr(10) & "Y=Shutdown N=Postpone 30 minutes",4,"Automatic Shutdown Notification")
If constConf = 7 Then
objActive.Terminate
Wscript.Sleep(1800000)
Else
objActive.Terminate
Exit For
End If
Next
Thanks for any help!
Shell.Run returns an integer, so you can't call a method (Terminate) on its return value. You also can't Set it since it's not an object.
You can call your shutdown script by just running it. Give it the full path, however, not a relative path. Scripts launched from Task Scheduler often have different "starting folders" than those launched manually so don't rely on your script finding the other one relatively.
Also, you'll have to add Chr(34) before and after your path to account for any spaces.
strForceShutdown = "c:\path\to\ForceShutdown.vbs"
wshShell.Run Chr(34) & strForceShutdown & Chr(34)
Finally, why launch the script and then ask whether to shutdown? Why not just launch your script after the user has responded and then you don't have to worry about terminating a running process.

VBS WScript.Run fails after passing Exists test

In a couple of place in my code I check if the file exists (it does) then I try to Run the file as above, or get the DateLastModified, and get errors about file not found or invalid path. How can the script NOT see a file after confirming it exists?
I'm working up a .vbs script that tries to run an Access .mdb file. The WScript.Run command seems to choke on the filename, but putting a MsgBox() before that call to display the path allows Run to work properly. I don't want to display a popup.
Error is:
The directory name is invalid.
How is this possible and how can I get around it?
Here is code:
AccessFileName = "App.mdb"
LocalPath = "C:\Folder\"
SET ws = WScript.CreateObject("WScript.Shell")
path = Chr(34) & LocalPath & AccessFileName & Chr(34)
if (fso.FileExists(LocalPath & AccessFileName)) THEN
'MsgBox(path) 'Uncommenting this line removes the error
ws.Run path 'This line errors
End If
Try to open your file with shell .InvokeVerb method:
AccessFileName = "App.mdb"
LocalPath = "C:\Folder\"
If CreateObject("Scripting.FileSystemObject").FileExists(LocalPath & AccessFileName) Then
CreateObject("Shell.Application").Namespace(LocalPath).ParseName(AccessFileName).InvokeVerb
End If
UPD: Both ActiveX WScript.Shell and Shell.Application uses native windows shell to perform a file execution.The first one launches new process via WSH core located in wscript.exe, cscript.exe, wshom.ocx, jscript.dll, vbscript.dll, ets, .Run and .Exec methods of WsShell object provides wide control on the launched process, and second one located in Shell32.dll, uses .InvokeVerb method of IShellDispatch object, called without name, runs default verb equals to the windows explorer "open" command.In case of any issues connected to WSH, explorer might still works without any proplems. If it does, that is just a work-around, I can't say what's wrong definetely without close look.
Hello the following code worked for me.
Basically this code gets a folder object and loops through all files in a folder and checks if its the one that you named. This it runs the application.
Set fso = CreateObject("Scripting.FileSystemObject")
Set ws = Wscript.CreateObject("Wscript.Shell")
AccessFileName = "App.mdb"
LocalPath = "C:\Folder\"
Set myFolder = fso.GetFolder(LocalPath)
For each myFile in myFolder.Files
If myFile.Name = AccessFileName Then
'Wscript.Echo myFile.Name
ws.Run myFolder.Path & "\" & myFile.Name
End If
Next
You can give this a shot. You probably do not need the quotes around the path, but I included it as a comment if you want to give it a shot. You just put quotes twice if you need to include a quote character in a string:
Set fso = CreateObject("Scripting.FileSystemObject")
AccessFileName = "App.mdb"
LocalPath = "C:\Folder\"
Set ws = WScript.CreateObject("WScript.Shell")
' path = """" & LocalPath & AccessFileName & """" <-- probably unnecessary
path = LocalPath & AccessFileName
If (fso.FileExists(path)) Then
Set file = fso.GetFile(path)
'MsgBox(path) 'Uncommenting this line removes the error
ws.Run file.Path 'This line errors
End If
This does not make any sense. Having a MsgBox line is altering the behavior of the program!!!
I feel it is probably some weird invisible character somewhere which is getting activated when you comment the line.
Try retyping the If block without the MsgBox in between.

how to check vbs script in windows is running or not?

I have created a VBS script in Windows. I will run this script to get size of a file.
I made this to run for ever. (even this is my requirement).
How should I know if it is running or stopped?
------ Exact Script starts here -----
Set FSO = CreateObject("Scripting.FileSystemObject")
Set FSO_check=CreateObject("Scripting.FileSystemObject")
do while infiniteLoop=0
----- This code is lasting for ever ----
Loop
Am i clear in my ques?
How about using the commandline property? I think this need Windows XP and up.
For example:
Set objSWbemServices = GetObject ("WinMgmts:Root\Cimv2")
Set colProcess = objSWbemServices.ExecQuery _
("Select * From Win32_Process where name = 'wscript.exe'")
For Each objProcess In colProcess
WScript.Echo objProcess.Name, _
objProcess.ProcessId, _
objProcess.CommandLine
Next
I made a script and at the beginning i wanted to avoid having multiple / duplicate instances of the same process running. This is my code to quit the newer instance in case it gets launched when already running.
Note: This does note prevent multiple wscripts files from running - just prevents the same particular file from having simultaneous instances.
To adapt to suit the original question... just use the block which checks current running processes, if the any of the wscript file names equal the script file you're looking for, then it's running.
function duplicate_check
'if two scripts get here at the same time - stagger when the generate _
'the list of running processes _
'ie - give 1 of them time to close
'else they can both quit leaving no more scripts running
call random_script_sleep(2500,500)
dim myfilename
myfilename = Wscript.ScriptName
strComputer = "."
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcesses = objWMIService.ExecQuery("select * from win32_process")
'fill arrary w/ all running script names
i = 0
For Each objProcess in colProcesses
If objProcess.Name = "wscript.exe" Then
strScriptName = Trim(Right(objProcess.CommandLine,Len(objProcess.CommandLine) - InstrRev(objProcess.CommandLine,"\")))
strScriptName = Left(strScriptName, Len(strScriptName) - 1)
a(i)= strScriptName '
i=i+1
end if
Next
'kill script if already running w/ same name
if i > 1 then 'if > 1 wscript instance
for s = 0 to i
if a(s) = myfilename then
wscript.quit
end if
next
end if
'sometimes duplicate check fails, if so, write to error log
If Err.Number = 1 Then
error_notes = " #duplicate check, firstdupcheck(0/1):" & firstdupcheck
call error_log
error_notes = "error undefined"
end if
' if debugmsg = 1 then CreateObject("WScript.Shell").Popup _
' "found this many scripts: " & i & vbCrlf & _
' "<>" & i & vbCrlf & _
' ", 1, "debug popup"
end function
#nimizen answer is not correct. If you have another wscript running, it will return that your script is already running.
#h pic answer is correct, but I get an error with the "a" array in my windows. So I changed it a little and cleaned to work.
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colProcesses = objWMIService.ExecQuery("select * from win32_process where name = 'wscript.exe'")
i = 0
For Each objProcess in colProcesses
if not (IsNull(objProcess.CommandLine )) then
strScriptName = Trim(Right(objProcess.CommandLine,Len(objProcess.CommandLine) - InstrRev(objProcess.CommandLine,"\")))
strScriptName = Left(strScriptName, Len(strScriptName) - 1)
if strScriptName = Wscript.ScriptName then
i=i+1
end if
if i > 1 then 'if > 1 wscript instance
'Wscript.Echo "Duplicate :"&strScriptName&" ."
Wscript.Quit
end if
end if
Next
'Wscript.Echo "Pause 2 have 2 scripts running ."
Hmm, well first if its an infinite loop script, then you're probably using it to periodically check a folder to do some work. This sounds bad but is usually less resource intense than hooking into WMI for notifications. If its up and running, its running. The real problem is discriminating it from all the other WScript and CScripts scripts you may have running.
MS Sysinternals Process Explorer http://technet.microsoft.com/en-us/sysinternals/bb896653 is good at telling you information about your running processes. Mostly I would use it to tell by unique command line arguments which script process is hosting which script.
There is no easy way to exactly find your script's process Id from within a script. It is one of the few pieces of runtime information not exposed in the script environment's object model. Since you are already using the File System Object perhaps you could have it look for a dummy file name to use as the indicator that it is running. If the script couldn't create or open the file then you could assume that another instance of the script is already running.
Or have another unique named dummy file that you can easily create and your script automatically deletes during its processing run. That way you simply create an empty file of that name as a test and if it doesn't disappear in a few seconds you know no instances of your script are running.
Also I was thinking that you could launch your script from another script using Exec() which returns the ProcessID of the launched script and then release your reference to it, storing the ProcessID wherever you need it for later use.
Set oExec = WshShell.Exec( "infinite.vbs" )
MyProcessID = oExec.ProcessID ' procID of shell'd program.
set oExec = Nothing
and do something with MyProcessID
Then I noticed this posting
Find my own process ID in VBScript
Which uses Exec() to run an HTA script, get its ProcessID and look that up in WMI, then use the result set from WMI to locate the Parent process' ProcessID which should be the script making the Exec() and WMI calls. The problem with it is the HTA may terminate before WMI gets a chance to find it.
Dim iMyPID : iMyPID = GetObject("winmgmts:root\cimv2").Get("Win32_Process.Handle='" & CreateObject("WScript.Shell").Exec("mshta.exe").ProcessID & "'").ParentProcessId
Mostly I get the feeling that this is all overkill for whatever reason you think you need to know if the script is running. Instead focus on what action "knowing if the process is running or not" causes you to take. Since that hasn't been explained we really can't offer you an alternative strategy to get you there, but I'm sure a more simple solution is available. TheFolderSpy http://venussoftcorporation.blogspot.com/2010/05/thefolderspy.html for example would be one alternative way to run your program without an infinite loop.
Don't forget to use a sleep command in your loop to let other programs get work done. It makes a great difference in resource use. Also you only need one FSO instance, make it global to all your code by creating it early on in your script before any subroutines.
Since you are looking at the size of a file, you are probably checking it for changes. I've found that a loop with a small WScript.Sleep 200 delay in it is good to detect if a file is done being altered. That way you can process the file instead of having to skip it until the next main loop pass which should be set to 10 seconds or more.

Run a vbscript from another vbscript

How do I get a vbscript to run another vbscript?
Id imagine its only a few lines of code but not tried doing this before, nothing is passed between the 2, one just needs to call/run the other.
For examples the script being run is called TestScript.vbs, the other script for it to call/run would be called Secondscript.vbs, both of which are located in C:\Temp.
Thanks
Mark
See if the following works
Dim objShell
Set objShell = Wscript.CreateObject("WScript.Shell")
objShell.Run "TestScript.vbs"
' Using Set is mandatory
Set objShell = Nothing
You can try using the Wshshell.Run method which gives you little control of the process you start with it. Or you could use the WshShell.Exec method which will give you control to terminate it, get a response, pass more parameters (other than commandline args), get status, and others
To use Run (Simple Method)
Dim ProgramPath, WshShell, ProgramArgs, WaitOnReturn,intWindowStyle
Set WshShell=CreateObject ("WScript.Shell")
ProgramPath="c:\test run script.vbs"
ProgramArgs="/hello /world"
intWindowStyle=1
WaitOnReturn=True
WshShell.Run Chr (34) & ProgramPath & Chr (34) & Space (1) & ProgramArgs,intWindowStyle, WaitOnReturn
ProgramPath is the full path to your script you want to run
ProgramArgs is the arguments you want to pass to the script. (NOTE: the arguments are separated by a space, if you want to use an argument that contains a space then you will have to enclose that argument in quotes [Safe way to do this is use CHR (34) Example ProgramArgs= chr (34) & "/Hello World" & chr (34)])
IntWindowStyle is the integer that determines how the window will be displayed. More info on this and WaitOnReturn can be found here WshShell.Run Method
WaitOnReturn if true then the script will pause until the command has terminated, if false then the script will continue right after starting command.
NOTE: The Run method can return the exit code but you must set WaitOnReturn to True, and assign the 'WshShell.Run' to a variable. (EX: ExitCode=WshShell.Run (Command,intWindowStyle,True))
To Use EXEC (Advanced Method)
Dim ProgramPath, WshShell, ProgramArgs, Process, ScriptEngine
Set WshShell=CreateObject ("WScript.Shell")
ProgramPath="c:\test run script.vbs"
ProgramArgs="/hello /world"
ScriptEngine="CScript.exe"
Set Process=WshShell.Exec (ScriptEngine & space (1) & Chr(34) & ProgramPath & Chr (34) & Space (1) & ProgramArgs)
Do While Process.Status=0
'Currently Waiting on the program to finish execution.
WScript.Sleep 300
Loop
ProgramPath same as Run READ RUN'S DESCRIPTION
ProgramArgs DITTO
ScriptEngine The Engine you will be using for executing the script. since the exec method requires a win32 application, you need to specify this. Usually either "WScript.exe" or "CScript.exe". Note that in order to use stdin and stdout (we'll cover what these are a bit further down) you must choose "CScript.exe".
Process this is the Object that references to the program the script will start. It has several members and they are: ExitCode, ProcessID, Status, StdErr, StdIn, StdOut, Terminate.
More Details about the members of Process Object
ExitCode This is the exit code that is returned when the process terminates.
ProcessID This is the ID that is assigned to the process, every process has an unique processID.
Status This is a code number that indicates the status of the process, it get set to '-1' when the process terminates.
StdErr This is the object that represents the Standard Error Stream
StdIn This is the Object that represents the Standard Input Stream, use it to write additional parameters or anything you want to pass to the script you are calling. (Process.StdIn.WriteLine "Hello Other Worlds")
StdOut This is the Object that represents the Standard Output Stream, It is READONLY so you can use Process.StdOut.ReadLine. This is the stream that the called script will receive any information sent by the calling script's stdin. If you used the stdin's example then StdOut.Readline will return "Hello Other Worlds". If there is nothing to read then the script will hang while waiting for an output. meaning the script will appear to be Not Responding Note: you can use Read or ReadAll instead of ReadLine if you want. Use Read (X) if you want to read X amount of characters. Or ReadAll if you want the rest of the stream.
Terminate Call this method to force terminate the process.
For more information about WshShell.Exec go to Exec Method Windows Scripting Host
Just to complete, you could send 3 arguments like this:
objShell.Run "TestScript.vbs 42 ""an arg containing spaces"" foo"
You can also load the body of the script and execute it within the same process:
Set fs = CreateObject("Scripting.FileSystemObject")
Set ts = fs.OpenTextFile("script2.vbs")
body = ts.ReadAll
ts.Close
Execute body
In case you don't want to get mad with spaces in arguments and want to use variables try this:
objshell.run "cscript ""99 Writelog.vbs"" /r:" & r & " /f:""" & wscript.scriptname & """ /c:""" & c & ""
where
r=123
c="Whatever comment you like"
I saw the below code working.
Simple, but I guess not documented.
Anyone else used the 'Execute' command ?
Dim body, my_script_file
Set Fso = CreateObject("Scripting.FileSystemObject")
Set my_script_file = fso.OpenTextFile(FILE)
body = my_script_file.ReadAll
my_script_file.Close
Execute body
Try this.
Option Explicit
On error resume next
Dim Shellobj
Set Shellobj = CreateObject("WScript.Shell")
Shellobj.Run "Test.vbs"
Set Shellobj = Nothing
As Martin's Answer didn't work at all for me ("File not found") and atesio's Answer does not allow to call two scripts which include repeating variable definitions, here is another alternative which finally worked for me:
filepath = Chr(34) & "C:\...\helloworld.vbs" & Chr(34)
Set objshell= CreateObject("WScript.Shell")
objshell.Run "wscript " & filepath, , True
Set objshell= Nothing
(Windows 8.1)

Resources