set batch script for loop to NOT wait for previous iteration to complete - windows

I have the following script which launches multiple sessions of RDP connection files at once (colleted from a folder which only contains rdp files).
If I launch this from cmd prompt, it launches all sessions in parallel (which is what I want)
for /r %i in (*.rdp) do (mstsc %~nxi /f)
**while **if i run this script, it just launches the first session then waits for the relative process to end before running the second connection and so on.
for /r %%i in (*.rdp) do (mstsc %%~nxi /f)
What I'm doing wrong? Shouldn't it be the default behavior of batch to run all commands in parallel?
I've checked this but it doesn't address my exact scenario and it doesn't work anyhow as expected (e.g. START myBatchScript.bat doens't change the "waiting for process" behavior)
EDIT
Added answer based on comments (Thanks to #Compo and #Modi)

The coding solution to replicate the cmd behavior as a batch script is using the "start" command (as below, thanks to #Compo)
#for /r %i in (*.rdp) do #(start "" mstsc "%~nxi" /f)
for the reason why this happens refer to #Mofi comments.

Related

How do I load multiple programs in a Windows batch script?

I'm trying to create a batch file to load multiple Window programs, more specifically, applications that control peripheral flight hardware.
I can't seem to figure out how to open up all applications consecutively. I've tried a number of things including running the executable application:
#echo off
cd "D:\Controls\" & start "D:\HW_Controls\Control1.exe" &
cd "D:\Controls\" & start "D:\HW_Controls\Control2.exe" &
cd "D:\Controls\" & start "D:\HW_Controls\Control3.exe"
That would only run one application at a time, until I exit that application, which is what I don't want. I want them to open consecutively. So I read somewhere on StackOverflow from an old post to try running each application as its own batch file like so:
#echo off
start "D:\Controls1.bat" &
start "D:\Controls2.bat" &
start "D:\Controls3.bat"
In which each batch file within looks similar to this:
cd "D:\Controls\" & start "D:\HW_Controls\Control{1..3}.exe"
I've also tried using chdir:
chdir "D:\Controls\" & start "D:\HW_Controls\Control{1..3}.exe"
When I try to load the batch file within, it doesn't appear to change the directory, and loads only opens a command prompt where the initial batch file is located, in this case, the Desktop directory.
I know there are options to open them on Windows startup, but that's not what I want. I want to load them up when I need to use the applications.
BONUS POINTS: If someone can tell me how to exit all the applications in a batch script as well when I'm finished with them.
The batch parser works line by line. & is used to write two commands in one line. So it doesn't make sense to end a line with a &.
For readability, the use of & should be limited.
cd should be used with the /d switch to be able to switch to another drive.
start takes the first quoted parameter as a window title, so give it a pseudo title.
start has a /d parameter to set the working folder, so you don't need cd at all:
So your batch file simplifies to:
#echo off
start "" /d "D:\Controls\" "D:\HW_Controls\Control1.exe"
start "" /d "D:\Controls\" "D:\HW_Controls\Control2.exe"
start "" /d "D:\Controls\" "D:\HW_Controls\Control3.exe"
echo press any key to kill the program.
pause >nul
taskkill /im "Control1.exe"
taskkill /im "Control2.exe"
taskkill /im "Control3.exe"
Note: taskkill sends a termination signal to the application. If it does not answer correctly by closing itself, you can force-close it with the /f switch.
Here's one method to launch multiple programs at once:
#For %%A in ("notepad.exe" "chrome.exe" "calc.exe") do start "" %%~A

Read variable from external file not working on running as scheduled task

I would like to run a batch file after resuming from sleep state in Windows.
If I start the batch file on command line everything works as expected.
But the batch script does not run properly as scheduled task.
What I have done:
External config file AutoMountConf.bat contains set Pass = Test
Local script file scheduleTask.bat contains
rem AutoMountConf.bat is in my intranet.
call X:\AutoMountConf.bat
start "" "C:\Program Files\TrueCrypt\TrueCrypt.exe" /auto favorites /p %Pass% /q
On command line the TrueCrypt container is mounted.
If I run the script from scheduled task I get the login screen to type the password manually.
There are two or perhaps even three issues.
The first one is set Pass = Test instead of set "Pass=Test" as Stephan reported already. For more details on how to assign a value right to an environment variable see my answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line?
The second issue is caused by the fact that network drives once mapped by a user to a drive letter and remembered in registry by Windows are automatically disconnected by Windows on user logs off and are only reconnected if the same user logs on again.
For a scheduled task it is therefore very often necessary to use UNC paths for files and folders on a shared folder in network or connect the network drive and disconnect it in the batch file itself executed as scheduled task.
It is not possible to call a batch file with UNC path. Windows does not allow that. Therefore it is necessary to connect and disconnect to network share manually in the batch file. I offer 2 solutions for this problem.
The first one is using command net use:
%SystemRoot%\System32\net.exe use X: \\ComputerName\ShareName password /user:Domain\UserName /persistent:no
if not errorlevel 1 (
call X:\AutoMountConf.bat
%SystemRoot%\System32\net.exe use X: /delete
start "" /wait "C:\Program Files\TrueCrypt\TrueCrypt.exe" /auto favorites /p %Pass% /q
)
password and /user:Domain\UserName is necessary only if the scheduled task is not executed with a user account which has the permissions to access the batch file on the remote machine. In general it is much more secure to define the scheduled task with the right user account and safe the password also for this account together with the task. Windows stores the password for the task encrypted like it does it also for the user account itself.
Run in a command prompt windows net use /? for details on the required and optional options. /persistent:no is what avoids remembering the network share in Windows registry for automatic reconnect after login by same user.
The second one is using commands pushd and popd:
pushd \\ComputerName\ShareName
if not errorlevel 1 (
call AutoMountConf.bat
popd
start "" /wait "C:\Program Files\TrueCrypt\TrueCrypt.exe" /auto favorites /p %Pass% /q
)
Please execute in a command prompt window pushd /? and read the output help to understand why this works.
But this solution requires that the user account used for the scheduled task with correct password is one which has appropriate permissions on the share on the remote computer. Password and user name can't be specified with this solution in the batch file itself.
if not errorlevel 1 means if previous command exited NOT with a value greater or equal 1 meaning if exit code of previous command is 0 and therefore command execution was successful. It can always happen that the remote machine is currently not available on network and therefore it is always good to check success on connecting to share on remote machine.
There is perhaps one more reason why Pass is not defined after running AutoMountConf.bat.
AutoMountConf.bat contains setlocal and the variable Pass is defined after this command was executed and before endlocal is executed in same batch file or implicitly called by command processor on exiting AutoMountConf.bat.
setlocal results in creating always a copy of existing environment variables and all modifications on environment variables are done on this local copy. The previous environment variables are restored on execution of (matching) endlocal or when end of a batch file is reached in which case the command processor automatically restores previous environment.
Please execute in a command prompt window setlocal /? and read the output help.
For examples to understand environment management by commands setlocal and endlocal perhaps even better see answers on Echoing a URL in Batch and Why is my cd %myVar% being ignored?
set Pass = Test
sets a variable pass<space> with the Content <space>Test. So %pass% keeps empty.
use this Syntax:
set "Pass=Test"
to avoid any unintended spaces.

Kill batch file in such a way that its children are killed too, in Windows

I need to start an exe from a cmd (wrap the exe so I can supply some command-line options). The problem is that just calling the exe from the cmd does not make the wrapping completely transparent: if the .exe hangs, killing the cmd won't kill the exe. I need it to kill the exe too. Can I do that in plain Windows (from XP up), without adding any dependencies?
In Bash you have exec which replaces the shell process with the supplied command. This is handy for writing wrapper scripts, making the wrapping process completely transparent. I know Windows lacks execve() to make this possible, but I'm only interested in the parent-killing-its-children part.
CLARIFICATION: I'm not looking for ways to kill the exe, I am looking for ways to wrap (start) the exe so that killing it using standard ways (eg. Ctrl+C or from task manager) works. For instance, I could create a lnk file (Windows shortcut) and get this behavior, but I want to do it from a script (for one, lnks only work with absolute paths, I can't deploy that).
Thanks.
Taskkill can be used to match certain criteria. By entering Taskkill/? you get the manual and can read up on how to filter using common properties. I assume that all your children share a common portion in their name. You could use taskkill to math the name with wildcards and close all children that matched that name.
EDIT (taken from the comments section):
As IInspectable points out you can kill all child processes using the /T flag.
EDIT starting from a batch you could use START (reference here) to launch the exe parallel to the batch and have your abort in the batch.
Edit i wrote and tested this mini example:
#echo off
echo starting %1
start %1
echo Any key to kill execution
pause >> NUL
taskkill /IM %1 /t
taskkill /F /IM iexplore.exe
/F to force kill.
Which can kill subprocesses
e.g. https://www.windows-commandline.com/taskkill-kill-process/

Restore default working dir if bat file is terminated abruptly

I have a scenario where during execution of a batch file, it navigates to a different folder (say to "../asdf"); and at the end of execution it will set the current working dir as the same folder from where the user called the .bat file.
But if the user terminates the batch processing before it is complete, the cmd show the current working dir (say "../asdf").
But in my case, I need to restore the working dir to the default/predefined one. Is it possible?
Batch file is written by me, so I can modify it.
CMD is opened through a desktop shortcut to CMD, which I have control of; so properties like working dir or passing args to CMD etc can be done there.
In your batch script use setlocal to encapsulate the running environment of your batch session. If the user terminates the script before you cd or popd to return, your script will still exit in the directory in which it started. Here's a brief test:
#echo off
setlocal
pushd c:\Users
cd
exit /b
Output:
C:\Users\me\Desktop>test.bat
c:\Users
C:\Users\me\Desktop>
Notice I didn't popd or cd %userprofile%\Desktop, but I still ended up back at my Desktop after the script exited.
Additionally, setlocal keeps you from junking up your environment with orphaned variables that mean nothing outside of your batch script. It's just good practice. At the console, type help setlocal for more info.

Pausing a batch file when double-clicked but not when run from a console window?

Is there a way for a batch file (in this case, running on Windows XP) to determine whether it was launched from a command line (i.e. inside a console window) or launched via the shell (e.g. by double-clicking)?
I have a script which I'd like to have pause at certain points when run via the shell, but not when run at a command line. I've seen a similar question on SO, but am unable to use the same solution for two reasons: first, whether or not it pauses needs to be dependent on multiple factors, only one of which is whether it was double-clicked. Second, I'll be distributing this script to others on my team and I can't realistically ask all of them to make registry changes which will affect all scripts.
Is this possible?
Found one :-) – After desperately thinking of what cmd might do when run interactively but not when launching a batch file directly ... I finally found one.
The pseudo-variable %cmdcmdline% contains the command line that was used to launch cmd. In case cmd was started normally this contains something akin to the following:
"C:\Windows\System32\cmd.exe"
However, when launching a batch file it looks like this:
cmd /c ""C:\Users\Me\test.cmd" "
Small demo:
#echo off
for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set DOUBLECLICKED=1
if defined DOUBLECLICKED pause
This way of checking might not be the most robust, though, but /c should only be present as an argument if a batch file was launched directly.
Tested here on Windows 7 x64. It may or may not work, break, do something weird, eat children (might be a good thing) or bite you in the nose.
A consolidated answer, derived from much of the information found on this page (and some other stack overflow pages with similar questions). This one does not rely on detecting /c, but actually checks for the name of the script in the command line. As a result this solution will not pause if you double-clicked on another batch and then called this one; you had to double-click on this particular batch file.
:pauseIfDoubleClicked
setlocal enabledelayedexpansion
set testl=%cmdcmdline:"=%
set testr=!testl:%~nx0=!
if not "%testl%" == "%testr%" pause
The variable "testl" gets the full line of the cmd processor call, stripping out all of the pesky double quotes.
The variable "testr" takes "testl" and further strips outs the name of the current batch file name if present (which it will be if the batch file was invoked with a double-click).
The if statement sees if "testl" and "testr" are different. If yes, batch was double-clicked, so pause; if no, batch was typed in on command line (or called from another batch file), go on.
Edit: The same can be done in a single line:
echo %cmdcmdline% | findstr /i /c:"%~nx0" && set standalone=1
In plain English, this
pipes the value of %cmdcmdline% to findstr, which then searches for the current script name
%0 contains the current script name, of course only if shift has not been called beforehand
%~nx0 extracts file name and extension from %0
>NUL 2>&1 mutes findstr by redirecting any output to NUL
findstr sets a non-zero errorlevel if it can't find the substring in question
&& only executes if the preceding command returned without error
as a consequence, standalone will not be defined if the script was started from the command line
Later in the script we can do:
if defined standalone pause
One approach might be to create an autoexec.nt file in the root of c:\ that looks something like:
#set nested=%nested%Z
In your batch file, check if %nested% is "Z" - if it is "Z" then you've been double-clicked, so pause. If it's not "Z" - its going to be "ZZ" or "ZZZ" etc as CMD inherits the environment block of the parent process.
-Oisin
A little more information...
I start with a batch-file (test.cmd) that contains:
#echo %cmdcmdline%
If I double-click the "test.cmd" batch-file from within Windows Explorer, the display of echo %cmdcmdline% is:
cmd /c ""D:\Path\test.cmd" "
When executing the "test.cmd" batch-file from within a Command Prompt window, the display of
echo %cmdcmdline% depends on how the command window was started...
If I start "cmd.exe" by clicking the "Start-Orb" and "Command Prompt" or if I click "Start-Orb" and execute "cmd.exe" from the search/run box. Then I execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:
"C:\Windows\system32\cmd.exe"
Also, for me, if I click "Command Prompt" from the desktop shortcut, then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is also:
"C:\Windows\system32\cmd.exe"
But, if I "Right-Click" inside a Windows Explorer window and select "Open Command Prompt Here", then execute the "test.cmd" batch-file, the display of echo %cmdcmdline% is:
"C:\Windows\System32\cmd.exe" /k ver
So, just be careful, if you start "cmd.exe" from a shortcut that contains a "/c" in the "Target" field (unlikely), then the test in the previous example will fail to test this case properly.

Resources