Batch run script when closed - windows

My question is how would I make a batch script instead of closing when the X in the top right is pressed to execute a file called exit.exe.

There are a couple points in this question that are not clear enough:
If you want that when the rigth top X is pressed on the cmd.exe window it not close, but do a different thing instead, then there is no way to achieve such thing with any existent window, that is, with the windows of all existent applications.
If you want to differentiate if the window that execute your Batch file terminated normally or terminated because the user click on the right top X, then the way to achieve that is via a previous "starter" program that execute your Batch file and expects a certain value returned from it. If the returned value is not the expected one, then it is assumed that the window was cancelled via the right top X.
starter.bat:
#echo off
echo Start yourScript.bat:
start "" /W yourScript.bat
echo Value returned from the script: %errorlevel%
if %errorlevel% neq 12345 ECHO execute exit.exe
yourScript.bat:
#echo off
echo I am the script.bat
set /P var=input value:
rem Terminate normally:
exit 12345

the [X] is "out of reach" for cmd. Only way, I can think of is: create another cmd to watch the presence of the current window:
#echo off
title WatchMe
more +7 %~f0 >t2.bat
start "watcher" t2.bat
exit /b
#echo off
:running
tasklist /v|find "WatchMe" >nul &&echo waiting || goto finished
timeout 1 >nul
goto running
:finished
echo "the process has finished

Related

How to start of commands with auto response to prompt in batch script

I am trying the following:
start /wait /B "C:\Users\Kiriti_Komaragiri\Desktop\sample" npm i
echo Y
start /wait /B "C:\Users\Kiriti_Komaragiri\Desktop\sample2" npm i
I would like to run the above in the same window with auto response "Y"
Currently, its running only the first command and not the third one. I am not sure why?
Here you go.
echo Y | start /wait /B "C:\Users\Kiriti_Komaragiri\Desktop\sample" npm i
echo Y | start /wait /B "C:\Users\Kiriti_Komaragiri\Desktop\sample2" npm i
More information please. What type of command are you trying to feed the response to? Is it Choice, Set /p, or something else your trying to feed a response to?
Without knowing more, the only suggestion I can make requires the existence of a label before the input is processed in the secondary batch.
A workaround exists whereby you can call and arrive at a label in another Batch by calling a label with the same name in your calling Batch. This allows you to define the value of the input (Whatever form the input takes) in your primary batch, then do as follows (substituting label names, variable names and file paths as appropriate)
-In the Calling (Primary) Batch:
Set ResponseVarName=Y
Call :targetLabel
(whatever code your batch has in between)
REM this is where you make your hack 'Call' to the other batch, without actually 'Calling' the batch itself.
:targetLabel
%userprofile%\desktop\yourotherbatch.bat
exit /b
Just to be sure your absolutely clear, this workaround is utterly dependant on being sent to a specific label after the response is set, BEFORE other commands are executed.
(EDIT-) A couple of example programs to show the concept:
::::::::: %userprofile%\desktop\HomeBatch.bat ::::::::::::::::
#ECHO OFF
:main
Set TestEnvironment=1
Call :targetLabel
:nottarget
ECHO NOT target
pause
exit
:targetLabel
%userprofile%\desktop\OtherBatch.bat npm i
:homeBatch
ECHO returned Home
pause
GOTO main
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::::::::: %userprofile%\desktop\OtherBatch.bat ::::::::::::::::
#ECHO OFF
:NottheTarget
ECHO NOT THE TARGET
pause
exit
:targetLabel
ECHO Found the Target. TestEnvironment=%TestEnvironment% %~1 %~2
pause
Exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Batch which carries out a command when a button is pressed while running a loop

I want to run a loop and have it so that if a certain key is pressed the loop ends, something like what is below although that does not work.
Also the loop has to continue running and not stop while waiting for a input from the user.
#echo off
:start
echo 1
IF "a"=="" GOTO end
goto :start
:end
pause
This works automatically in all batch scripts, as long as the certain key is Ctrl+C.
Otherwise, you need a check at each iteration of your loop (like you have), and another process to monitor the keyboard.
:: Allocate a probably-unique filename
set SENTINELFILE=%temp%\sentinel-%random%-%time:~6,5%.lck
:: Should probably do something less destructive if the file already exists
:: like loop and find another name. But this is a prototype.
copy /y NUL %SENTINELFILE%
:: Opens a new cmd window which prompts the user to press X
:: then deletes the sentinel and exits
:: Could also run another batch file or exe that does something we can detect
start "End Task" %comspec% /c choice /c x /M "Press X to end task" ^& del %SENTINELFILE%
:topofloop
:: TODO: Process some part of your work to be done
:: Loop as long as the sentinel file exists
if exist %SENTINELFILE% goto :topofloop
What you are referring to is multi-thread (one thread taking input and one running the loop). There are a few tricky ways of doing this. However, to save you time and effort, a cheap trick you can do is hold the loop every iteration for a second and wait for input using the choice command:
#echo off
:start
echo 1
choice /c "qa" /d q /t 1 /n /m "Press a to Stop Loop: "
if %errorlevel%==2 goto end
cls
goto :start
:end
pause
Which will stop it once a second to check for input as a

Command to auto-exit a batch if left idle?

I was wondering if there was a command to automatically exit a batch file if it is left alone for a certain number of seconds.
I made a little program similar to the one found here. Most of the coding I used is displayed on the page, but it basically asks you what website you want to visit, and selecting one of the options opens a browser window with the desired page. however, after selecting one of the listed sites, the program displays the options to either exit or return to the top. This is where I usually forget about it until I close whatever I was looking at, and the batch is still open in the background.
So is there anyway to set a auto-exit timer without it interrupting the user, and without restricting the ability to go back and select another option?
Thanks!
You can use choice command, instead set /p
Where z is an automatic option, you can use another letter.
/D is the default option if time is passed.
/T is the time to wait (this case, 5 seconds).
choice /n /c:zbe /T 5 /D x /M "Make your selection"
Then use it on your code:
choice /n /c:xbe /T 5 /D x /M "Make your selection"
if errorlevel 1 exit
if errorlevel 2 goto :option_b
if errorlevel 3 goto :option_e
More info type in cmd:
choice /?
Please take a look here
set /p udefine=
this line is waiting for b or e
Since you only want to exit the batch file after selecting one website, you can just wipe these lines
echo Type [e] to exit or [b] to go back and select another site.
echo.
set /p udefine=
echo.
echo ***************************************************************
if %udefine%==b goto top
if %udefine%==e goto exit
:exit
cls
echo ***************************************************************
and also this line (before the last one)
pause

If not exists then exit + cmd

i try to make a loop in a .cmd file.
If test.txt is not exists then i will kill the cmd process.
#echo off
if not exists test.txt goto exit
But this code doesn't work and i don't know how to make a loop every 2 seconds.
Thanks for help.
The command is called exist, not exists:
if not exist test.txt goto :exit
echo file exists
:exit
About your loop:
I am not 100% sure, but I think there is no sleep or wait command in Windows. You can google for sleep to find some freeware. Another possibility is to use a ping:
ping localhost -n 3 >NUL
EDIT:
The Windows Server 2003 Resource Kit Tools contains a sleep.
See here for more information, too
If you need to wait some seconds use standard CHOICE command. This sample code check if file exist each two seconds. The loop ends if file exists:
#ECHO OFF
:CHECKANDWAITLABEL
IF EXIST myfile.txt GOTO ENDLABEL
choice /C YN /N /T 2 /D Y /M "waiting two seconds..."
GOTO CHECKANDWAITLABEL
:ENDLABEL
exit is a key word in DOS/Command Prompt - that's why goto exit
doesn't work.
Using if not exist "file name" exit dumps you out of that batch file.
That's fine if exiting the batch file is what you want.
If you want to execute some other instructions before you exit, change the label to something like :notfound then you can goto notfound
and execute some other instructions before you exit.
(this is just a clarification to one of the examples)
Using the following:
if not exist "file name" goto exit
Results in:
The system cannot find the batch label specified - exit
However using the same command without "goto" works, as follows:
if not exist "file name" exit

How to make windows batch file pause when double-clicked?

I've written a batch file to automate some tasks. I can run it from a command window and it runs and displays results. If I double click it from explorer though, it runs and terminates immediately so I can't see the results.
Is there a way I can make batch file window stay open until I dismiss it if I started it by double-clicking the icon?
I don't want to have to pass a /nopause parameter or something when I call a batch file from the command line. I'd like a solution where I can use the batch file without having to do anything too special?
Thanks.
NOTE I don't want it to pause when running from the command line!! I may call this batch file from another batch file to carry out a load of operations. In that case I can't be sitting there to keep hitting enter.
Ideally it would be best if I can put some code in the batch file so it can work out where it was started from, and then pause or not as appropriate.
Use:
cmd /K myBatch.bat
as your shortcut.
My problem was similar - I wanted a pause at the very end if called from Windows Explorer, but no pause if in a command window. I came up with this.
At the top of every batch file, put this:
if "%parent%"=="" set parent=%~0
if "%console_mode%"=="" (set console_mode=1& for %%x in (%cmdcmdline%) do if /i "%%~x"=="/c" set console_mode=0)
and then at end
if "%parent%"=="%~0" ( if "%console_mode%"=="0" pause )
It handles nested batch calls, where you only want to pause at the end of the original batch file, not in nested batch files. In a nested batch file, %parent% is already set to original caller so it won't equal the nested %~0. If you have bat1 which calls bat2, it leaves open the option of double clicking bat2 in Explorer - in that context bat2 will pause at end, whereas if bat1 calls bat2, then bat2 won't pause at the end (only bat1 will pause).
The & statement separator helps avoid visual clutter for something which is secondary to the main function. If you don't like the look of it, just put each statement on a new line.
This approach looks for /C as one of the params in the launch command (%cmdcmdline%). It assumes your batch files don't use the /C option. If you use /C yourself, then you need to instead check if %COMSPEC%appears within %cmdcmdline% (use FINDSTR). When Explorer launches a bat file, its %cmdcmdline% includes %COMSPEC% eg C:\Windows\System32\cmd.exe /C double_clicked_batch_file_name. In a command window, %cmdcmdline% just has cmd.exe in it (no path). I use CALL mybat rather than cmd.exe /C mybat, but you may have to work with existing batch files.
Here is a solution that should work well and take into consideration the possibility that a batch-file might call another batch-file ("Nested").
You could use Find, to look for "/c" which should not be present if the batch-file is run from a "Command Prompt":
echo %cmdcmdline% | find /i "/c"
But, you could do a more "robust" test by using Find to search for a longer string, or the batch-file name.
The "Find" command will not work properly if the search string has (") double-quotes within it. To work around that, you can use environment variable substitution to "adjust" the string so it plays nice with Find:
set newcmdcmdline=%cmdcmdline:"=-%
This will typically return:
if the batch-file is run from a "Command Prompt"
newcmdcmdline=-C:\Windows\system32\cmd.exe-
if the batch-file is run by clicking on the the batch-file
(or the batch-file shortcut) from "Windows Explorer"
newcmdcmdline=cmd /c --D:\Path\test.cmd- -
Then you can use "Find" to test like:
echo %newcmdcmdline% | find /i "cmd /c --"
or
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
Next, you need to decide if you want a "Nested" batch-file to behave as if you executed it in the same way as the calling batch-file, or if you want nested batch-files to always behave as if they were executed from a "Command Prompt".
Consider that if you are running in a nested batch-file, then testing for this:
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
will always fail (no match) because %newcmdcmdline% contains the name of the outermost batch-file, not the nested batch-file.
So the first solution will behave the same for the calling batch-file, and all nested batch-files. Also perfect if you don't call any batch-files:
In all batch-files (calling and nested) that you care to make this test, add these lines, typically near the top of the batch-files (you may exclude the echo-statements if you wish):
if not defined withincmd call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from within a Command Prompt
rem if %withincmd% EQU 0 pause
Then, somewhere within each batch-file, add the testshell sub-function:
goto :EOF
:testshell
rem "Nested" batch-files won't see this because withincmd is already defined
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
You only make the conditional call to "testshell" one time, at the top of the outermost batch-file.
In some situations, you may want to have only the "outermost" batch-file behave differently if it is executed from a "Command Prompt" versus if it is run by clicking on the the batch-file (or the batch-file shortcut) from "Windows Explorer". So, batch-files called from the "outermost" batch-file will always behave the same regardless of how they are run.
For this to work, you have a few choices.
1) Save the value of "withincmd" before you call another batch-file, and restore the previous value of "withincmd" after the called batch-file returns. This is a little involved for most cases.
2) Use a "globally-unique" variable name for "withincmd" in each batch-file.
3) Execute the "Find" command each time you need to know how the current batch-file was run.
4) Increment a variable on entry to a batch-file and decrement it on batch-file exit, then only test how batch-file was run if count-variable=1
Method 3 is the easiest, but has the downside that if the outermost batch-file is called from itself (as in recursion) or another batch-file, the test variable (withincmd) will not be properly set.
Here's how to do it using method 3:
In all batch-files (calling and nested) that you care to make this test, add these lines, typically near the top of the batch-files (you may exclude the echo-statements if you wish):
call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from (or Nested) within a Command Prompt
rem if %withincmd% EQU 0 pause
Then, somewhere within each batch-file, add the testshell sub-function:
goto :EOF
:testshell
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
In this case, you have to call "testshell" once, at the top of the EACH batch-file, then again after you have returned from calling another batch-file (or call "testshell" each time you need to know how the current batch-file was run).
Here's how to do it using method 4:
In all batch-files (calling and nested) that you care to make this test, add these lines, typically near the top of the batch-files (you may exclude the echo-statements if you wish):
if not defined nestinglevel set nestinglevel=0
set /A nestinglevel=nestinglevel+1
call :testshell
if %withincmd% EQU 0 echo This batch-file: %~dpf0 was executed directly (from Windows Explorer, ...).
if %withincmd% EQU 1 echo This batch-file: %~dpf0 was executed from (or Nested) within a Command Prompt
rem if %withincmd% EQU 0 pause
Then, somewhere within each batch-file, add the testshell sub-function:
goto :EOF
:testshell
if not defined newcmdcmdline set newcmdcmdline=%cmdcmdline:"=-%
set withincmd=1
if %nestinglevel% GEQ 2 goto :EOF
echo %newcmdcmdline% | find /i "cmd /c --%~dpf0%-"
if %errorlevel% EQU 0 set withincmd=0
goto :EOF
Also, remember to decrement the variable when you exit one batch-file to return to the calling batch-file:
set /A nestinglevel=nestinglevel-1
In this case, you have to call "testshell" once, at the top of the EACH batch-file, then again after you have returned from calling another batch-file (or call "testshell" each time you need to know how the current batch-file was run).
In all cases, test %withincmd% to determine how the current batch-file was run, like this:
if %withincmd% EQU 0 pause
if %withincmd% EQU 1 goto :EOF
at the end of file print
pause
it will wait for anykey input
Add this at the end of your batch:
echo %CMDCMDLINE% | findstr /C:"/c">nul && pause
This will pause if run from Windows Explorer and do nothing if run from command line.
Explanation:
CMDCMDLINE contains "/c" when run from Windows Explorer.
echo %CMDCMDLINE% | will pipe contents of the CMDCMDLINE into findstr
findstr /C:"/c" checks if CMDCMDLINE contains "/c"
">nul" will discard findstr console output
&& pause will run only if findstr finds something
you can just add params to the batch call and handle conditionally pause statement in your batch. So when started from command line or dblclick the batch can pause, when called from others batches with a /nopause param don't pause.
use "pause" in the batch file at the end, and it will wait for the user input
HTH
Would the pause command work?
Microsoft Documentation on pause

Resources