VBScript file stops immediately after executing non local executable - vbscript

I have two files in one folder, a vbs file called notify.vbs and an executable called foo.exe.
the foo.exe is a node.js pkg-bundled executable that triggers a native desktop notification with a random message from a local text file after 5 seconds from execution. Although pkg had one inconvencience which is that executing foo.exe launches a cmd interface, which doesn't suit my purpose. This is where notify.vbs come in handy as it can execute foo.exe while keeping the cmd interface hidden just like I wanted. notify.vbs looks like this:
Set oShell = CreateObject("Shell.Application")
oShell.ShellExecute "foo.exe", , , "runas", 1
It works fine. But then, when I change the location of foo.exe for example in a folder called bar directly in the C drive and change the path in the script to:
Set oShell = CreateObject("Shell.Application")
oShell.ShellExecute "C:\bar\foo.exe", , , "runas", 1
the script starts foo.exe and closes it immediately.
Basically notify.vbs only executes foo.exe when they're in the same folder. When I change the location of either of them it does that weird behaviour I mentioned. I verified the functionality of foo.exe in different locations. It always works. I even verified the path in script each time I tried a different location, it's always correct as it actually does execute foo.exe but it closes it immediately after.
I have no experience with VBScript as I copy pasted that script. Thanks in advance.

Related

How to give script a name?

I have a script that I run to keep my computer from going to sleep. It's a simple script that presses the Num Lock key. How can I give my script a name so I can see it in Task Manager? I would like to end the process every now and then and not sure which application it is.
Here is the code (idle.vbs):
Dim objResult
Set objShell = WScript.CreateObject("WScript.Shell")
Do While True
objResult = objShell.sendkeys("{NUMLOCK}{NUMLOCK}")
Wscript.Sleep (60000)
Loop
Your script is being executed in an interpreter, and in Task Manager you will see the name of the executable : wscript.exe
You cannot change the process name, although you can identify the name of the running script using another script and the property of handles.
But the easiest way would be to make a copy of the executable wscript.exe, rename it with something suggestive for you, and use that executable in cmd to run the script. For example idleEx.exe and run it :
...\idleEx.exe idle.vbs
Or, the other method: create a shortcut for the vbs and change Properties / General / Opens with, browse and choose idleEx.exe.
After that, your process name will apear as idleEx.exe

On boot, issues running a bat file through vbs script

I need to run a program (a python script made into an exe) on start up, without the console showing up.
In some question, I found the solution, i.e to execute the program. Right now, I'm testing it out with a simple python program filewriter.py that does -
while count != 1000:
f = open('test.txt','a+')
f.write(str(count))
f.close()
sleep 1
The bat file tool.bat :
#ECHO OFF
python "<absolute_path_here>\filewriter.py"
EXIT /B
The VBS file :
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "<absolute_path_here>\tool.bat" & Chr(34), 0
Set WinScriptHost = Nothing
If I execute the VBS file (double-click it), everything works fine. The output file appears, without the console appearing. So I added it to registry under
HKCU\Software\Microsoft\CurrenVersion\Run
as WScript "path_to_the_vbs_file".
On Startup, the VBS file executes properly (verified it by adding a MsgBox which displayed the popup) but the call to the bat file is not being executed. How do I make this work?
In windows there are two python executables: python.exe, pythonw.exe. If you don't wish to see the terminal window you must use pythonw.exe.
I need to run a program (a python script made into an exe).
If you covert your script to .exe with help of py2exe it is simillar. You can assing your script to console or windows. Look to Py2exe Tutorial, the console variable can be replace forwindows.
You don't need to create EXE files from python. You can run pythonw.exe with path as argument to your script. Why do you need to create .bat which you run from vbscript ? Look here: Run on windows startup CMD with arguments
I forgot to say, that the Windows Python installer normally create following file association, so the script can run directly.
'.py' to python.exe
'.pyw' to pythonw.exe
Other way how you can run the the script on boot is to use Windows Scheduler. The big advantage is you can setup user rights or more events when start the script. You can run the script manually too and you will last status.
Create Python .exe is sometimes tricky. If you don't need to distribute your script to multiple computers I prefer don't use.

current working directory in a vbscript invoked by a drag & drop operation

When I was trying to get elevated rights for my batch script, when I found two related SO questions
How to request Administrator access inside a batch file
How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?
...that led to answers that worked partially. For some reason, I had issues with command line passing for file path arguments containing spaces within the VBS script, so I tried to break the solution into 3 parts and concentrated on the inner (VBS) step, then adding the last step by calling a batch from that VBS which could not be found, despite in the same folder as the VBS script. I found that drag & drop isn't "that easy" and that it's different when using .vbs instead of .bat or .exe as drop targets.
Here is my actual question:
If I drag a file and drop it onto an executable (exe) or batch file (bat, cmd), The current working directory is determined by the source of the dragged item. Its directory is set as the working directory for the program or script that processes it.
If I drop a file onto a VBS script, it's different. On Windows 8.1 x64 I observe it to be C:\Windows\System32 even if the argument resides in the same folder as the VBS.
I can simply use a batch file (as drag'n'drop relay) like this
my.vbs %*
to get "the normal" .bat behaviour (drop source dictates CWD), but I also want to understand it.
Is it a bug or a feature? Is it consistent over all Windows versions?
edit: added the background (on top) for the question showing how I got there (+minor corrections)
After some API monitoring, this is what I see
When you drop a file over a .exe file the explorer.exe uses CreateProcess API function to start the process, passing the executable as lpApplicationName, and the executable and dropped file as lpCommandLine. The lpCurrentDirectory is set in the function call by the caller process to the folder containing the dropped file[1].
When you drop a file over a .cmd file the explorer.exe also uses CreateProcess API, but in this case the lpApplicationName is null and the lplCommandLine contains the batch file and the dropped file. lpCurrentDirectory is also set to the parent folder of the dropped file[1].
When you drop a file over a .vbs file, ShellExecuteEx is used and the lpDirectory field of the SHELLEXECUTEINFO structure is null, so, the process created inherits the current active directory of the parent process. By default the current active directory of the explorer.exe process is %systemroot%\system32, but it is possible to start a explorer instance with a different current active directory that will be inherited in this kind of drop operations.
[1] If we drop more than one file, the path of the file passed as first argument is used
note just for information: to test the active directory inherit the process followed was:
Open a cmd instance and change the current active directory to c:\temp
Kill all explorer.exe instances
From the cmd instance call explorer.exe. This explorer instance has the active directory in the cmd window as its current active directory.
The Arguments property holds the full paths to all items dropped on the script, so you can determine the directory of each dropped item like this:
Set fso = CreateObject("Scripting.FileSystemObject")
For Each item In WScript.Arguments
WScript.Echo fso.GetParentFolderName(item)
Next
Assuming that the working directory would be defined by what is dropped onto a script is a misguided approach. If you require that logic you can implement it in the script yourself, though, e.g. like this:
Set fso = CreateObject("Scripting.FileSystemObject")
Set sh = CreateObject("WScript.Shell")
For Each item In WScript.Arguments
sh.CurrentDirectory = fso.GetParentFolderName(item)
'working directory is now the parent folder of the current item
'...
Next
If you need the working directory to be the parent directory of the VBScript file you can derive that from the ScriptFullName property:
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetParentFolderName(WScript.ScriptFullName)
If I lookup the file types in the Windows registry, I see the following in their Shell\Open\Command values:
batfile: "%1" %*
cmdfile: "%1" %*
exefile: "%1" %*
VBSFile: "%SystemRoot%\System32\WScript.exe" "%1" %*
This seems to suggest that bat, cmd, exe are treated as executable on their own, maybe for historical reasons, whereas VBS is considered an ordinary script, that is only executable because its extension is registered with some executable to be called to interpret it. Pretty much the same as Python or Perl.
[Update] Indeed I proved that a Python script shows exactly the same behaviour as my VBS script: calling it from the command line providing arguments keeps the CWD, dropping a file on it causes the CWD to be C:\Windows\System32. So my question seems to be sort of wrong, but finally it helped people to point me into the right direction for further research...
c:\windows\system32\CScript.exe or c:\windows\system32\Wscript.exe are the programs that run vbscript. As you can see they are in system32.
Windows uses ShellExecuteEx to start programs - see it's rules at MSDN: ShellExecuteEx function (Windows)
ShellExecuteEx uses CreateProcess (CreateProcessEx) to actually start a program. CreateProcess function (Windows)
Edit
CMD doesn't use the registry for it's own stuff. Those registry entries are for programs other than CMD.
CMD main goal is to be MS Dos 5 compatible while enhancing it, it will correctly run most DOS batch files. It was written by IBM engineers working on OS/2 NOT Windows.
Edit 2
The core of your problem is that you are attempting to write programs as if you are a user typing to operate a computer.
As a programmer you don't make assumptions. The easiest way to not take assumptions is to specify full paths to what you want. Your batch file shouldn't care what the current directory is. EG In CMD there is a current directory per drive for compatibility with MSDos 5 (and programs in a console tend to share them but don't have to). In Windows there is one current directory per program. The default current directory has changed over the years.
The only time you should work with the current directory is if you are writing a batchfile for a user to use. EG If you type dir it does the current directory, a batchfile meant to be a general command should work the same way.

VBS script (VBScript) errors 800A0035 and/or 800A004C only on the first execution of the script

I am pretty new to all this VBS stuff because basically all I need to do is to make one simple VBS script, which I have possibly written, however, my problem is that it gives me 800A0035 or 800A004C error when I execute it for the first time on a particular PC, as soon as I execute it for the second time, it runs just OK and does what it is supposed to do. Incidentally, on my own computer it works OK even on the first execution.
I know that the errors have something to do with the wrong paths but I have checked my script several times and I am 100% positive that they are correct.
Here is the script:
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.MoveFile "rar.bat" , "rarp.bat"
'HideBat.vbs
CreateObject("Wscript.Shell").Run "rarp.bat", 0, True
What the script is supposed to do is to rename the rar.bat file to rarp.bat and run that batch file (rarp.bat) without popping up the command prompt. What the batch file does is not relevant, I guess, but anyway, it just runs WinRAR.
The rar.bat file and the VBS script are in the same folder, that's why I have used relative paths in the script. I cannot use absolute paths because I need to run the script on several computers.
I have read somewhere on the internet that by default VBS script first looks for the files in C:\Windows\System32 when relative paths are used. I have even tried using absolute paths in the script but it didn't work either. Here is how I need them to look like: %systemdrive%\users\%username%\appdata\roaming\rar.bat but this simply didn't work in the VBS script.
I really think that what I need is really a simple script but apparently it's pretty hard to get it working properly. I will be very grateful to those who help me.
Thank you a lot in advance.
Regards.
The only way your script - at least the part published - can give an error is by not finding the source file for renaming, you should have added full script and error message to be sure.
I suppose this is caused by a security setting on your pc that are more forgiving than on the rest of the pc's, eg UAC ? On the other pc's, try to put the files in a map like c:\test and then run it again after checking that the file rar.bat does exist in the same map. Do you have the same credentials (admin) on the other pc's ?
If you just want to run the bat file hidden, why the renaming ?
how do you download the bat ? and how then is invoked the script ? could be a timing issue that the second time is no longer a problem. In that case check in your script if the file is allready there and do a sleep in a loop while it doesn't
If you want to use the absolute path you could try this
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")
Set WshSysEnv = WshShell.Environment("PROCESS")
path = WshSysEnv("USERPROFILE") & "\appdata\roaming\rar.bat"
wscript.echo path
objFSO.MoveFile path , "rarp.bat"
CreateObject("Wscript.Shell").Run "rarp.bat", 1, True

Hide Command Window of .BAT file that Executes Another .EXE File

This is a batch file in Windows.
Here is my .bat file
#echo off
copy "C:\Remoting.config-Training" "C:\Remoting.config"
"C:\ThirdParty.exe"
This works fine except the .bat file leaves the command window open the whole time the "ThirdParty" application is running.
I need the command window to close.
I would use the short-cut for the application but I must be able to run this copy command first (it actually changes which data base and server to use for the application).
The ThirdParty application does not allow the user to change the source of the db or the application server.
We're doing this to allow users to change from a test environment to the production environment.
Using start works for me:
#echo off
copy "C:\Remoting.config-Training" "C:\Remoting.config"
start C:\ThirdParty.exe
EDIT: Ok, looking more closely, start seems to interpret the first parameter as the new window title if quoted. So, if you need to quote the path to your ThirdParty.exe you must supply a title string as well.
Examples:
:: Title not needed:
start C:\ThirdParty.exe
:: Title needed
start "Third Party App" "C:\Program Files\Vendor\ThirdParty.exe"
Create a .vbs file with this code:
CreateObject("Wscript.Shell").Run "your_batch.bat",0,True
This .vbs will run your_batch.bat hidden.
Works fine for me.
Using start works fine, unless you are using a scripting language. Fortunately, there's a way out for Python - just use pythonw.exe instead of python.exe:
:: Title not needed:
start pythonw.exe application.py
In case you need quotes, do this:
:: Title needed
start "Great Python App" pythonw.exe "C:\Program Files\Vendor\App\application.py"
Try this:
#echo off
copy "C:\Remoting.config-Training" "C:\Remoting.config"
start C:\ThirdParty.exe
exit
Great tip. It works with batch files that are running a java program also.
start javaw -classpath "%CP%" main.Main
You might be interested in trying my silentbatch program, which will run a .bat/.cmd script, suppress creation of the Command Prompt window entirely (so you won't see it appear and then disappear), and optionally log the output to a specified file.
Or you can use:
Start /d "the directory of the executable" /b "the name of the executable" "parameters of the executable" %1
If %1 is a file then it is passed to your executable. For example in notepad.exe foo.txt %1 is "foo.txt".
The /b parameter of the start command does this:
Starts an application without opening a new Command Prompt window. CTRL+C handling is ignored unless the application enables CTRL+C processing. Use CTRL+BREAK to interrupt the application.
Which is exactly what we want.
I haven't really found a good way to do that natively, so I just use a utility called hstart which does it for me. If there's a neater way to do it, that would be nice.
Using Windows API we can start new process, a console application, and hide its "black" window. This can be done at process creation and avoid showing "black" window at all.
In CreateProcess function the dwCreationFlags parameter can have CREATE_NO_WINDOW flag:
The process is a console application that is being run
without a console window. Therefore, the console handle
for the application is not set. This flag is ignored if
the application is not a console application
Here is a link to hide-win32-console-window executable using this method and source code.
hide-win32-console-window is similar to Jamesdlin's silentbatch program.
There is open question: what to do with program's output when its window does not exist? What if exceptions happen? Not a good solution to throw away the output. hide-win32-console-window uses anonymous pipes to redirect program's output to file created in current directory.
Usage
batchscript_starter.exe full/path/to/application [arguments to pass on]
Example running python script
batchscript_starter.exe c:\Python27\python.exe -c "import time; print('prog start'); time.sleep(3.0); print('prog end');"
The output file is created in working directory named python.2019-05-13-13-32-39.log with output from the python command:
prog start
prog end
Example running command
batchscript_starter.exe C:\WINDOWS\system32\cmd.exe /C dir .
The output file is created in working directory named cmd.2019-05-13-13-37-28.log with output from CMD:
Volume in drive Z is Storage
Volume Serial Number is XXXX-YYYY
Directory of hide_console_project\hide-win32-console-window
2019-05-13 13:37 <DIR> .
2019-05-13 13:37 <DIR> ..
2019-05-13 04:41 17,274 batchscript_starter.cpp
2018-04-10 01:08 46,227 batchscript_starter.ico
2019-05-12 11:27 7,042 batchscript_starter.rc
2019-05-12 11:27 1,451 batchscript_starter.sln
2019-05-12 21:51 8,943 batchscript_starter.vcxproj
2019-05-12 21:51 1,664 batchscript_starter.vcxproj.filters
2019-05-13 03:38 1,736 batchscript_starter.vcxproj.user
2019-05-13 13:37 0 cmd.2019-05-13-13-37-28.log
2019-05-13 04:34 1,518 LICENSE
2019-05-13 13:32 22 python.2019-05-13-13-32-39.log
2019-05-13 04:55 82 README.md
2019-05-13 04:44 1,562 Resource.h
2018-04-10 01:08 46,227 small.ico
2019-05-13 04:44 630 targetver.h
2019-05-13 04:57 <DIR> x64
14 File(s) 134,378 bytes
3 Dir(s) ???,???,692,992 bytes free
Example shortcut for running .bat script
Target field:
C:\batchscript_starter.exe C:\WINDOWS\system32\cmd.exe /C C:\start_wiki.bat
Directory specified in Start in field will hold output files.
You can create a VBS script that will force the window to be hidden.
Set WshShell = WScript.CreateObject("WScript.Shell")
obj = WshShell.Run("""C:\Program Files (x86)\McKesson\HRS
Distributed\SwE.bat""", 0)
set WshShell = Nothing
Then, rather than executing the batch file, execute the script.
run it under a different user. assuming this is a windows box, create a user account for scheduled tasks. run it as that user. The command prompt will only show for the user currently logged in.
Compile the batch file to an executable using Batch2Exe http://www.f2ko.de/programs.php?lang=en&pid=b2e.
Use the "Invisible Window" option.
To make the command window of a .bat file that executes a .exe file exit out as fast as possible, use the line #start before the file you're trying to execute. Here is an example:
(insert other code here)
#start executable.exe
(insert other code here)
You don't have to use other code with #start executable.exe.
I used this to start a cmd file from C#:
Process proc = new Process();
proc.StartInfo.WorkingDirectory = "myWorkingDirectory";
proc.StartInfo.FileName = "myFileName.cmd";
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();
proc.WaitForExit();
Please use this one, the above does not work. I have tested in Window server 2003.
#echo off
copy "C:\Remoting.config-Training" "C:\Remoting.config"
Start /I "" "C:\ThirdParty.exe"
exit
So below vbscript will launch the cmd/bat file in hidden mode.
strPath = Wscript.ScriptFullName
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.GetFile(strPath)
strFolder = objFSO.GetParentFolderName(objFile)
'MsgBox(strFolder)
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run chr(34) & strFolder & "\a.bat" & Chr(34), 0
Set WshShell = Nothing
Now, only app window will be visible, not the cmd.exe window
This is an easy work around for those who are fine with a dirty solution. Press win+tab, drag and drop the bat file to a new desktop and forget about it.
I occasionally will make a bat file that I'll rarely use, and it is kind of a drag to have to use tools to make the window hidden. This is no more complicated than it needs to be for me.

Resources