I am looking to exit my loop at a defined number of loops (10 - Loops). I looked at a few things on Google, but the loop was to do something else, so I was a little lost.
Here is my basic loop script and I hope one of you can educate me and point me in the right direction. If your wondering what I am doing it this way, here's why and if you have a better option, please let me know. I am fairly new to this batch scripting and I am open to suggestions.
This Uninstaller.exe does not pause the batch script. So I am basically looking for the Uninstaller.exe, which will be deleted upon completion of the Uninstaller.exe process. So once the loop detects the deletion of the executable, it will then exit the loop and move on to the next action in the script.
I have had a couple times where the uninstaller.exe crashed before it ended and deleted its self and prevented the batch file from continuing on. So I figured it would be best to only have it loop for a set number of times before exiting.
:: Uninstall App
"C:\Program Files\App Name\uninstall.exe" -quiet
::Validates the uninstall
SET LookForUninstaller="C:\Program Files\App Name\uninstall.exe"
:CheckForUninstaller
IF NOT EXIST %LookForUninstaller% GOTO ExitLoop
TIMEOUT /T 5 >nul
GOTO CheckForUninstaller
:ExitLoop
You may benefit from using the "start" command to run the uninstaller on a different process.
And you may also take advantage of its optional "/WAIT" which will allow the batch to wait until the process is finished to continue.
You may not need the loop after all.
i.e.
start /WAIT "C:\Program Files\App Name\uninstall.exe"
Here is what I did and seems to work ok.
::Set Uninstaller Variable
SET AppToUninstall="C:\Program Files\App Name\uninstall.exe"
:: Uninstall App
"%AppToUninstall%" -quiet
::Loops for 12 times in 10 second intervals (Total 120 seconds) to confirm deletion. Loop will exit after 12 loops and move on if uninstaller is not deleted.
for /l %%i in (1,1,12) do (
TIMEOUT /T 10 >nul
IF NOT EXIST %AppToUninstall% GOTO ExitLoop
)
:ExitLoop
Related
I'm a computational biologist and I'm trying to run large batches of similar code with a single command, but my implementation has hit a brick wall.
I'm using the NEURON simulation environment, which uses MinGW for its Windows interface, which is where my research has shown my problem arises.
Currently, I am using a batch file to run all of these similar pieces of code, to iterate across the "collection" subfolders:
#echo off
for /D %%a in ("%cd%\all_cells\cell_*.*") do cd "%%a\sim1\" & START neuron sim.hoc
The problem arises when I have more than 32 subfolders; the additional instances won't run and will error with a "console device allocation failure: too many consoles" error.
My research has shown me that this is a known problem with Cygwin/MinGW.
However, working around this manually (ensuring that there is no more than 32 "collection" folders) is extremely time consuming when I am now dealing with hundreds of instances (each refers to a simulated cell and I want to gather statistics on hundreds of them), so I am trying to find a solution.
That said, I am terrible at writing batch files (I'm a terrible programmer who is used to scientific languages) and I can't figure out how to code around this.
It would be great if someone could help me either find a way around the 32 limit, or failing that, help me write a batch file that would do this:
-iterate over up to 32 folders
-wait for the instances to finish
-do it again for the next 32, until I reach the end of the folder.
I have tried using the /wait command to do them one at a time, but it still opens all 32. (And this wouldn't be ideal as I'd like to use all 16 cores I have.
The following is adapted from https://stackoverflow.com/a/11715437/1012053, which shows how to run any number of processes while limiting the total number run simultaneously in parallel. See that post for some explanation, though the code below is fairly well documented with comments.
I've eliminated the /O option and the code to work with PSEXEC from the original script.
The script below runs everything in one window - the output of each process is captured to a temporary lock file, and when finished, the full output of each process is typed to the screen, without any interleaving of process output. The start and end times of each process are also displayed. Of course you can redirect the output of the master script if you want to capture everything to a single file.
I've limited the total number of parallel processes to 16 - of course you can easily modify that limit.
The code will not work as written if any of your folder paths include the ! character. This could be fixed with a bit of extra code.
Other than that, the code should work, provided I haven't made any silly mistakes. I did not test this script, although the script it was derived from has been thoroughly tested.
#echo off
setlocal enableDelayedExpansion
:: Define the maximum number of parallel processes to run.
set "maxProc=16"
:: Get a unique base lock name for this particular instantiation.
:: Incorporate a timestamp from WMIC if possible, but don't fail if
:: WMIC not available. Also incorporate a random number.
set "lock="
for /f "skip=1 delims=-+ " %%T in ('2^>nul wmic os get localdatetime') do (
set "lock=%%T"
goto :break
)
:break
set "lock=%temp%\lock%lock%_%random%_"
:: Initialize the counters
set /a "startCount=0, endCount=0"
:: Clear any existing end flags
for /l %%N in (1 1 %maxProc%) do set "endProc%%N="
:: Launch the commands in a loop
set launch=1
for /D %%A in ("%cd%\all_cells\cell_*.*") do (
if !startCount! lss %maxProc% (
set /a "startCount+=1, nextProc=startCount"
) else (
call :wait
)
set "cmd!nextProc!=%%A"
echo -------------------------------------------------------------------------------
echo !time! - proc!nextProc!: starting %%A
2>nul del %lock%!nextProc!
cd "%%A\sim1\"
%= Redirect the output to the lock file and execute the command. The CMD process =%
%= will maintain an exclusive lock on the lock file until the process ends. =%
start /b "" cmd /c 1^>"%lock%!nextProc!" 2^>^&1 neuron sim.hoc
)
set "launch="
:wait
:: Wait for procs to finish in a loop
:: If still launching then return as soon as a proc ends
:: else wait for all procs to finish
:: redirect stderr to null to suppress any error message if redirection
:: within the loop fails.
for /l %%N in (1 1 %startCount%) do 2>nul (
%= Redirect an unused file handle to the lock file. If the process is =%
%= still running then redirection will fail and the IF body will not run =%
if not defined endProc%%N if exist "%lock%%%N" 9>>"%lock%%%N" (
%= Made it inside the IF body so the process must have finished =%
echo ===============================================================================
echo !time! - proc%%N: finished !cmd%%N!
type "%lock%%%N"
if defined launch (
set nextProc=%%N
exit /b
)
set /a "endCount+=1, endProc%%N=1"
)
)
if %endCount% lss %startCount% (
timeout 1 /nobreak >nul
goto :wait
)
2>nul del %lock%*
echo ===============================================================================
echo Thats all folks^^!
You could install screen or tmux in cygwin.
Then you can start all neuron instances in a screen/tmux session.
They will not open a new window, so there is no limit anymore.
I am coding a virus using some BSOD code (I didn't make that part of it) and I want the file to, one started, give itself admin privilages, set the date and time to a certain point, and once the system date and time hit a certain point, self destruct. The problem I'm coming accross is that, the file is stuck on the process of keeping the BSOD on the screen, so it never gets to the self destruct code. Any help would be greatly appreciated. Thanks.
I've tried looping it and putting the code to when the loop reaches a certain point, move on. Didn't work.
#echo off
set loopcount=1
:loop
(
echo ^<html^>^<head^>^<title^>Microsoft Windows^</title^>
echo.
echo ^<hta:application id="oBVC"
echo applicationname="BSOD"
echo version="1.0"
echo maximizebutton="no"
echo minimizebutton="no"
echo sysmenu="no"
echo Caption="no"
echo windowstate="maximize"/^>
(This is the beggining of the code. It should loop once, then self destruct itself)
start "" /wait "bsod.hta"
del /f /q "bsod.hta" > nul
set /a loopcount=loopcount-1
if %loopcount%==0 goto exitloop
goto loop
:exitloop
del "%~f0" & exit
(This is the part where it should have made itself self destruct after the loop happened)
I expected it to loop once, the self destruct, ending all processes. It just stayed on the process of holding up the BSOD
I expected it to loop once, the self destruct, ending all processes.
It just stayed on the process of holding up the BSOD
Your start /wait command will most certainly wait until the hta file has been closed prior to continuing execution of the rest of the batch file. If you wish to have the hta display and continue execution, just remove the /wait
start "bsod.hta"
I am creating a batch file program where if you open a mspaint.exe, if its idle for 10 seconds the program will close automatically. I have created this:
#echo off
:Start
tasklist /FI "IMAGENAME eq mspaint.exe" | findstr "mspaint.exe" >nul
IF "%ERRORLEVEL%" == "0" GOTO Running
IF "%ERRORLEVEL%" == "1" GOTO NotRunning
:Running
***::Check if idle***
GOTO Terminate
:NotRunning
GOTO EOF
:Terminate
timeout 5
taskkill /im mspaint.exe /f
ECHO Paint has been terminated due to inactivity
PAUSE
:EOF
EXIT
I have trouble finding the idle syntax(seems it doesn't exist), is there another way to make the idle time work? And since this is my first time creating a batch file, I really need a helping hand here.
Not the answer you want to hear, but the one that you need. The only way to monitor another process for activity is to install a window hook, but that's going to require a much lower level language (C or C++).
If that doesn't put you off then start with the Microsoft Hooks Overview and post further questions. Good luck (you'll probably need it).
Thanks for the help but that seems complicated. I used SCHTASKS instead and it worked :)
I hope that makes sense. I want to create a batch file or anything similar that will cycle through a few Processing applications for a presentation. Is there a way I can do this that will execute an application by time intervals, close before executing the next one, and then cycle back to the first application?
Certainly.
#ECHO OFF
SETLOCAL
:loop
FOR %%i IN ("process1.exe 20" "process2.exe 30" "process3.exe 10") DO CALL :cycle %%~i
GOTO loop
:cycle
START %1
timeout /t %2 >nul
TASKKILL /im %1 >nul
GOTO :eof
runs process1 for 20 sec, process2 for 30 - Got the pattern? The processes are terminated unceremoniously.
Press control-C and reply Y to terminate - will leave the last process invoked running.
Addendum:
TASKKILL knows nothing about "paths" - only the executable name.
hence, on the line after after the setlocal add
set path=C:\Users\MyName\Documents\School\Processing\Sketch_8\application.windows32;%path%
and specify the executable only in the FOR statement.
If there's more than one directoryname involved, just string them together with ; separators and ;%path% at the end.
Windows picks up the executable from the path by looking first in the current directory, then each directory on the path in turn until it finds the required executable. Adding the extra directories occurs only for the time this batch is running, and applies only to the batch's instance - it's not transmitted to any other process.
I want to perform the following operations.
Read 1 word at a time from an input file consisting of many words.
Pass this word as an argument to another command line based application.
Run that application for a fixed amount of time, say 10 seconds.
Abort the execution of the application if it is still running after 10 seconds and go back, pick the next word from the input file and repeat steps 1 to 3.
Here is what I have written though it does not achieve exactly what I want it to:
#echo off
for /f %%i in ('type input.txt') do call:Routine %%i
:Routine
set app="myApp.exe"
set limit=60
%app% %1
goto Delay
:Delay
ping localhost -n %limit% > nul
The above script will introduce the delay after the execution of myApp has completed. However, I want it to run myApp.exe for not more than 10 seconds, if it does, then abort the application using taskkill and move on to the next word from the input file.
I searched for a solution online and came across this:
http://www.tech-archive.net/Archive/WinXP/microsoft.public.windowsxp.general/2006-04/msg03609.html
Though it does not answer my query exactly, I would like to make my code do something similar.
Thanks.
The logic in the linked code looks flawed: It either launches 3 download commands, or it delays ~59 seconds and attempts to kill all download commands, but it never does both. The TASKKILL command arguments are not correct - the imagename belongs after the /IM parameter.
In your code, you are not going to kill your task without the TASKKILL command!
You must GOTO :EOF or EXIT /B after your loop finishes, otherwise the code will fall through and execute the subroutine without using CALL. But there really is no need to use a subroutine at all.
You only need to initialize your variables once.
No need to execute a command in your IN() clause. FOR /F has a variation that can read the text file directly. Type HELP FOR from the command line and read the documentation carefully.
PING has roughly a 1 second delay between each echo request. So a count of 11 will yield a delay of roughly 10 seconds.
EDIT - originally forgot the critical START command to start the app in its own process
#echo off
set app="myApp.exe"
set limit=11
for /f %%i in (input.txt) do (
start "" %app% %%i
ping localhost -n %limit% > nul
taskkill /im %app% /f
)