Possible to close executing bat file(s) pressing a button on keyboard? - batch-file

I had made an auto-backup for some videogame files and directorys. This little .bat just make a backup every 30 minutes. Now my problem is this: I want to close this window/process/file. Can I close it directly from itself if I press the X button on keyboard?
I've made this file on Win XP Home so please don't write commands that are only for WIN 10 or something else, if possible.
If it can be helpuful here is my .bat file code:
#echo off
:Minimize
if "%1" == "" start "" /min "%~f0" MY_FLAG && exit
:path ompressor
set d=%:\backup%
set e=%:\Documents and Settings\admin\Application Data\.minecraft%
:backup
set b=%date:/=%
set c=%time%
mkdir "C%d%\saves\%b%\%c%"
xcopy /s /e /y "C%e%\saves" "C%d%\saves\%b%\%c%"
set b=%date:/=%
set c=%time%
mkdir "C%d%\resorcepack\%b%\%c%"
xcopy /s /e /y "C%e%\resourcepacks" "C%d%\resorcepack\%b%\%c%"
msg * Worlds backupped!
:Countdown_Setup
set Days=0
set Hours=0
set Minutes=30
set Seconds=0
:Countdown
CLS
ECHO %Days% - %Hours% - %Minutes% - %Seconds%
ECHO Days Hours Mins Secs
sleep 1
IF "%Seconds%"=="0" (
IF "%Minutes%"=="0" (
IF "%Hours%"=="0" (
IF "%Days%"=="0" (
GOTO backup
)
SET /a Days -=1
SET Hours=24
)
SET /a Hours -=1
SET Minutes=60
)
SET /a Minutes -=1
SET Seconds=60
)
SET /a Seconds -=1
GOTO Countdown
Sorry if I ask a so unusual thing but I searched a lot on the net and I've tried a lot of commands like IF, SET, AT, TSKILL.
I'm a bit new on programming so please make something steb-by-step if you can.
Thanks in advance

Sounds to me like your script ia heavy on memory, but regardless.
In your main script, after #echo off add:
Title gamebackup
Create a new batch file called. Killgame.cmd
The simply add:
taskkill /F /FI "WindowTitle eq gamebackup*"
Then run the secondbatch to kill the process.

Related

Msgbox to prompt user if job (printing) is skip in batch

As suggested in my previous question, 1 question per thread. So Im here to open another question. Basically I want to prompt user that printing will be skip today because nothing to print, then the user will press OK, then code will continue to shutdown the computer. I want to do this to alert user that today's printing job have been run.
So I try some code like below, it seems working but i dont know how to implement in my main code.
#echo off
Call :Msgbox
if "%errorlevel%"=="1" GOTO SHUTDOWN
exit /b
:Msgbox
echo wscript.quit MsgBox ("Printing skipped.. Press ok to shutdow the computer", 48, "Shutdown Computer") >"%temp%\input.vbs"
wscript //nologo "%temp%\input.vbs"
exit /b
:SHUTDOWN
echo "%SystemRoot%\System32\shutdown.exe -s -t 60"
PAUSE
This is part of my main code where i want to place above code.
https://stackoverflow.com/a/57609600/6409413
IF pdf file size greater than 9000byte > Print PDF for today > Then go to Shutdown
IF pdf file size less than 9000byte > Promp user using msgbox > user press OK > Skip Print PDF for today > Then go to Shutdown
Rem ------------------------------------------------------------------------
Rem 4. Printing files with sizes over 9000 bytes
Set "_Exe1=%ProgramFiles(x86)%\Foxit Software\Foxit Reader\Foxit Reader.exe"
For %%A In ("%_Dir1%\c\%_FullDateString%.pdf")Do If %%~zA GTR 9000 (
Echo Printing %%A&Echo=&"%_Exe1%" /t "%_Dir1%\c\%_FullDateString%.pdf")
UPDATE:
Sort of working for now using code below. Any others way to achieve this?
Rem ------------------------------------------------------------------------
Rem 4. Printing files with sizes over 9000 bytes
Set "_Exe1=%ProgramFiles(x86)%\Foxit Software\Foxit Reader\Foxit Reader.exe"
setlocal EnableDelayedExpansion
For %%A In ("%_Dir1%\c\%_FullDateString%.pdf")Do ( set size=%%~zA
if !size! GTR 9000 (
goto PRINT
) else if !size! LSS 9000 (
goto NOPRINT
:NOPRINT
msg * /time:0 /w Printing skipped.. Press "OK" to shutdown the computer"
goto SHUTDOWN
)
)
:PRINT
Echo "Printing %%A&Echo=&"%_Exe1%" /t "%_Dir1%\c\%_FullDateString%.pdf")"
Rem ------------------------------------------------------------------------
Rem 5. Shutting down computer
:SHUTDOWN
echo "%SystemRoot%\System32\shutdown.exe -s -t 60"
PAUSE
I really think that you're overcomplicating this unnecessarily. You're already using the shutdown command, which can pop up a dialog box to the end user.
Rem ------------------------------------------------------------------------
Rem 4. Printing files with sizes over 9000 bytes
Set "_Exe1=%ProgramFiles(x86)%\Foxit Software\Foxit Reader\Foxit Reader.exe"
Set "_Msg=skipped"
For %%A In ("%_Dir1%\c\%_FullDateString%.pdf")Do If %%~zA GTR 9000 (
Set "_Msg=finished"&Echo Printing %%A&Echo=
"%_Exe1%" /t "%_Dir1%\c\%_FullDateString%.pdf")
Rem ------------------------------------------------------------------------
Rem 5. Shutting down computer
ShutDown /S /T 60 /C "Printing %_Msg%, shutting down your computer." /D P:0:0
Note: This section is a direct replacement for the previous code I provided, it is not based upon whatever you've posted above, (which is littered with issues).

Abort external process if it takes too long to complete

I am writing a batch script which processes many files at once using an external Python script. I'd like to implement a feature where, if the Python script hangs on any file for too long (e.g. the file is corrupted), the Python script will terminate and the batch script will move onto the next file. I have seen others on this site suggest using a timeout for terminating a program after a certain amount of time; however, that is far from ideal for this scenario, as that will add that many seconds to the running time of the script for each tile.
My question is: is there a way to limit the running time of an external process, without causing a delay if the process completes before the time is up?
Here is a bit of my code. TexIDfix.py at the end is the Python script which I need to prevent from hanging. Any help is much appreciated :)
:fixer
for /f %%f in ('dir /b "workspace\content\patch\data\fighter\%1\model\%3"') do (
set val=%%f
set val=!val:~1!
if /I !val!==01 set val=1
if /I !val!==02 set val=2
if /I !val!==03 set val=3
if /I !val!==04 set val=4
if /I !val!==05 set val=5
if /I !val!==06 set val=6
if /I !val!==07 set val=7
if /I !val!==08 set val=8
if /I !val!==09 set val=9
set /a "val=val*4"
if /I !val! GTR 255 (
set /a "mod/=255"
echo !mod!
set /a "val=val-(255*mod)"
echo !val!
)
TexIDfix.py "workspace\content\patch\data\fighter\%1\model\%3\%%f\%2.nud" "workspace\content\patch\data\fighter\%1\model\%3\%%f\model.nut" !val!
)
goto:eof

After terminate the batch needs to delete a .lock file that has been create

Hello I am very new in this and I was able to run one instance of a batch file.
However, another file is being created called something.lock but the file is not been deleted by itself when I stop the batch or close it.
The new file create is the one that helps to have one instance running.
Can the new file ".lock " be deleted after I close the script with the "X" or because an user ended correctly with going to label end:
The code that I have is
:init
set "started="
2>nul (
9>"%~f0.lock" (
set "started=1"
call :start
)
)
#if defined started (
del "%~f0.lock"
) else (
cls
ECHO Only one instance is allowed
timeout /NOBREAK /T 3 >nul
cls
)
exit /b
:start
cd /d %~dp0
cls
:initial
pause >nul
You are misapplying the lock file. You are simply checking to see if the file exists, which means you must guarantee that the file is deleted upon batch termination.
There is a much better way, which you have only partially implemented. Only one process can have the file open for write access. You just need to determine if the file is already locked by another process.
Once the process with the exclusive lock terminates, the lock will be released. This is true no matter how the script terminates - even if it was the result of Ctrl-C or window closure. The file might not be deleted, but the next time the script runs, the file won't be locked, so the script will proceed nicely.
In the code below I save the current definition of stderr to an unused file handle before I redirect sterr to nul. Within the inner block I redirect stderr back to the saved definition. In this way I prevent the error message if the file is already locked, but the CALLed :start routine will still print out error messages normally.
#echo off
:init
8>&2 2>nul ( 2>&8 9>"%~f0.lock" call :start ) || (
cls
ECHO Only one instance is allowed
timeout /NOBREAK /T 3 >nul
cls
)
del "%~f0.lock" 2>nul
exit /b
:start
cd /d %~dp0
cls
del asdfasdfasdf
:initial
pause >nul
The difficulty is that your batch thread itself won't have its own PID. There's no graceful way to tell whether your batch script is running or when it has terminated. And there's no way to wake the dead, to let the script have the last word when a user red X's or Ctrl+C's. When it's over, it's over.
There are a few ways you can do what you want to do. Try them all and see which you prefer. Use dbenham's solution. His is correct. The following efforts are left here as an exercise in futility, although Solution 4 seems to work very well. In the end, it's still just a hack; whereas dbenham's redirection sleight-of-hand provides a correct implementation of lock files the way lock files are supposed to work.
...
Solution 1
One simple way is to use powershell to minimize the current window, re-launch your script with start /wait, then after completion call powershell again to restore.
#echo off
setlocal
set "lock=%temp%\~%~n0.lock"
if "%~1" neq "wrapped" (
if exist "%lock%" (
echo Only one instance is allowed.
timeout /nobreak /t 3 >NUL
exit /b
)
rem :: create lock file
>"%lock%" echo 1
rem :: minimize this console
powershell -windowstyle minimized -command ""
rem :: relaunch self with "wrapped" argument and wait for completion
start /wait "" cmd /c "%~f0" wrapped
rem :: delete lock file
del "%lock%"
rem :: restore window
powershell -windowstyle normal -command ""
goto :EOF
)
:: Main script goes here.
:loop
cls
echo Simulating script execution...
ping -n 2 0.0.0.0 >NUL
goto loop
This should be enough for casual use and should account for any cause of the batch file's termination short of taskkill /im "cmd.exe" /f or a reboot or power outage.
Solution 2
If you need a more bulletproof solution, you can get the current console window's PID and intermittently test that it still exists. start /min a helper window to watch for its parent window to die, then delete the lock file. And as long as you're creating a watcher anyway, might as well let that watcher be the lock file.
Biggest drawback to this method is that it requires to end your main script with exit to destroy the console window, whether you want it destroyed or not. There's also a second or two pause while the script figures out its parent's PID.
(Save this with a .bat extension and run it as you would any other batch script.)
#if (#a==#b) #end /* JScript multiline comment
:: begin batch portion
#echo off
setlocal
:: locker will be a batch script to act as a .lock file
set "locker=%temp%\~%~nx0"
:: If lock file already exists
if exist "%locker%" (
tasklist /v | find "cleanup helper" >NUL && (
echo Only one instance allowed.
timeout /nobreak /t 3 >NUL
exit /b
)
)
:: get PID of current cmd console window
for /f "delims=" %%I in ('cscript /nologo /e:Jscript "%~f0"') do (
set "PID=%%I"
)
:: Create and run lock bat.
>"%locker%" echo #echo off
>>"%locker%" echo setlocal
>>"%locker%" echo echo Waiting for parent script to finish...
>>"%locker%" echo :begin
>>"%locker%" echo ping -n 2 0.0.0.0^>NUL
>>"%locker%" echo tasklist /fi "PID eq %PID%" ^| find "%PID%" ^>NUL ^&^& ^(
>>"%locker%" echo goto begin
>>"%locker%" echo ^) ^|^| ^(
>>"%locker%" echo del /q "%locker%" ^&^& exit
>>"%locker%" echo ^)
:: Launch cleanup watcher to catch ^C
start /min "%~nx0 cleanup helper" "%locker%"
:: ==================
:: Rest of script
:: blah
:: blah
:: blah
:: ==================
:end
echo Press any key to close this window.
pause >NUL
exit
:: end batch portion / begin JScript
:: https://stackoverflow.com/a/27514649/1683264
:: */
var oShell = WSH.CreateObject('wscript.shell'),
johnConnor = oShell.Exec('%comspec% /k #echo;');
// returns PID of the direct child of explorer.exe
function getTopPID(PID, child) {
var proc = GetObject("winmgmts:Win32_Process=" + PID);
return (proc.name == 'explorer.exe') ? child : getTopPID(proc.ParentProcessID, PID);
}
var PID = getTopPID(johnConnor.ProcessID);
johnConnor.Terminate();
// output PID of console window
WSH.Echo(PID);
Solution 3
You can also test a lock file and see whether it's stale by setting a timestamp within the lock file, and setting that same timestamp in your console window title. Only problem with this is that the window title doesn't revert to normal if the user terminates with Ctrl+C, so you can't run the script twice without closing the cmd window. But closing the window and opening a new one for subsequent launches may not be too terrible a price to pay, as this is the simplest method described thusfar.
#echo off
setlocal
set "started=%time%"
set "lockfile=%temp%\~%~n0.lock"
if exist "%lockfile%" (
<"%lockfile%" set /P "locktime="
) else (
set "locktime=%started%"
)
tasklist /v | find "%locktime%" >NUL && (
echo Only one instance allowed.
timeout /nobreak /t 3 >NUL
exit /b
)
title %~nx0 started at %started%
>"%lockfile%" echo %started%
:: rest of script here
echo Simulating script execution...
:loop
ping -n 2 0.0.0.0 >NUL
goto loop
Solution 4
Here's a bit more polished solution, combining methods 1 and 3. It re-launches itself in the same window, then sets the window title to a unique ID. When the script exits gracefully, the lock file is deleted. Whether the script exits gracefully or forcefully, the window title reverts back to its default. And if no window exists in the task list with a title matching the unique ID, the lock file is deemed stale and is overwritten. Otherwise, the script notifies the user that only one instance is allowed and exits. This is my favorite solution.
#echo off
setlocal
if "%~1" neq "wrapped" (
cmd /c "%~f0" wrapped %*
goto :EOF
)
:: remove "wrapped" first argument
shift /1
:: generate unique ID string
>"%temp%\~%~n0.a" echo %date% %time%
>NUL certutil -encode "%temp%\~%~n0.a" "%temp%\~%~n0.b"
for /f "usebackq EOL=- delims==" %%I in ("%temp%\~%~n0.b") do set "running_id=%%I"
del "%temp%\~%~n0.a" "%temp%\~%~n0.b"
set "lockfile=%temp%\~%~n0.lock"
if exist "%lockfile%" (
<"%lockfile%" set /P "lock_id="
) else (
set "lock_id=%running_id%"
)
tasklist /v | find "%lock_id%" >NUL && (
echo Only one instance allowed.
timeout /nobreak /t 3 >NUL
exit /b
)
title %running_id%
>"%lockfile%" echo %running_id%
:: rest of script here
echo Press any key to exit gracefully, or Ctrl+C to break
pause >NUL
del "%lockfile%"
goto :EOF

How to start a batch file when a text file is created?

I am trying to work out how to run a batch file when a text file is created. I have tried to research but am unable to find anything that helps.
The Pseudocode of what I want is something like this:
When "Response.txt" is created run "2 Week.bat".
Thanks.
#echo off
:start_loop
if exist "c:\Response.txt" (
start cmd /c "c:\2weeks.bat"
goto :exodus
)
rem :: wait for 1 minute
w32tm /stripchart /computer:localhost /period:1 /dataonly /samples:60 >nul 2>&1
goto :start_loop
:exodus
This will work on Vista and later:
#echo off
:loop
if exist "c:\folder\Response.txt" "c:\folder\2 week.bat"
rem - reduce CPU usage by waiting for 15 seconds
timeout /t 15 /nobreak
goto :loop

How to stop a bat file from running if there is no response

I have a bat file that I created, it adds keys to the windows registry and then calls another bat file, QGIS.bat (this bat file starts an application called QGIS).
It works most of the time but every now and then, when it calls QGIS.bat nothing happens, the command window stays open but QGIS (started by the QGIS.bat file) will not start.
In the command window(cmd) all it says is call .\usbgis\apps\qgis\bin\qgis.bat
(Just a note QGIS is a portable application that runs from a USB memory stick, might that be part of the problem?)
So my question. Is there a way you can terminate a bat file if it douse not close in 3 min or if the other bat file douse not start?
Thanks,
This is what I'm talking about in my comment:
#echo off
setlocal enabledelayedexpansion
set sPath=C:\Program Files\Internet Explorer
set sprog=iexplore.exe
set inc=0
:loop
if exist "%sPath%\%sProg%" (echo %sProg%) else exit /b
set /a inc+=1
if "!inc!" equ "30" (Echo Exiting & exit /b)
for /f %%a in (
'tasklist /NH /FI "Imagename eq %sProg%"^|findstr /i "INFO:"') do (
if not errorlevel 1 (
ping -n 11 127.0.0.1>nul
goto :loop
)
)
Obviously change the path and file to match yours. I just needed something for testing here.

Resources