TIMEOUT.EXE alternative for legacy Windows OSes? - windows

I am trying to write a batch script that is as universal across Windows versions as possible (or at least from XP to 10). Everything is compatible so far (just some echoes and variable setting), except it uses the TIMEOUT.EXE command, which isn't available in XP or below.
I tried copying the exe over to no success. I was wondering if, through some clever coding, if this is possible. I basically need it to wait X amount of seconds before continuing, or allow a keypress to continue.
I tried using sleep.exe from the server 2003 utilities pack while piping it to set /p "=" and vice versa, but that didn't work either.
Any help is appreciated.

There is the choice command command that offers a default option together with a timeout.
For instance:
rem /* Wait for 10 seconds and take the default choice of `0`;
rem you can interrupt waiting with any of the keys `0` to `9` and `A` to `Z`;
rem you cannot use punctuation characters or white-spaces as choices: */
choice /C 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ /D 0 /T 10
rem // The `ErrorLevel` value is going to be set to a non-zero value.

Not the greatest of tools, but using choice with a custom message and a timeout of (5 seconds in this demo), with keystroke interrupt (any key, besides Enter esc etc.)
#echo off
choice /c qwertyuiopasdfghjklzxcvbnm1234567890 /cs /n /M "Timeout is 5 seconds.. press any key to Continue." /D c /T 5
echo 1 > null

there are a lot of ways. PING seems to be the most popular. You can try also
with w32tm
w32tm /stripchart /computer:localhost /period:5 /dataonly /samples:2 1>nul
or wtih typeperf:
typeperf "\System\Processor Queue Length" -si 5 -sc 1 >nul
with mshta:
start "" /w /b /min mshta "javascript:setTimeout(function(){close();},5000);"

Related

How to execute multiple programs in the same time with a .bat file

I made 2 bat files to start apps with examples below:
My expectation is to execute them simultaneously, meaning after double click bat file, then 3 programs will pop up.
With the 1st example, the behavior is to execute outlook first, then both Mircrosoft Edge and OneNote still not pop up, until I stop Outlook.
Example 1
#echo off
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Outlook.lnk"
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\OneNote.lnk"
exit
With the 2nd example, both Mrcrosoft Edge and OneNote were executed simultaneously, however Outlook not until I stop OneNote.
Example 2
#echo off
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\OneNote.lnk"
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Outlook.lnk"
exit
My questions is why it behaves like this way and how to make these 3 programs start up in the same time ?
Shown below is the Windows config:
Edition Windows 10 Enterprise
Version 21H2
Installed on ‎10/‎27/‎2021
OS build 19044.1826
Experience Windows Feature Experience Pack 120.2212.4180.0
1)Run the first program using the start command.
2)Check the task list in a loop to see if the program has appeared there.
3)Impose some time limitation to the said loop.
4)Run the next program in case of success, exit with notification otherwise.
#ECHO
OFF START program1.exe
FOR /L %%i IN (1,1,100) DO (
(TASKLIST | FIND /I "program.exe") && GOTO :startnext
:: you might add here some delaying
)
ECHO Timeout waiting for program1.exe to start
GOTO :EOF
:startnext
program2.exe
:: or START
program2.exe
Remember that the timing is not precise, especially if you are going to insert delays between the task list checks.
Normally to run tasks parallel, you should add start /b before the command to run.
The start command allows the command to be executed in another process, while /b prevents the opening of a new window.
In this specific case start /b does not work, for reasons unknown to me, but you can always use cmd /c.

Batch to check if process exists

I'd like a batch that will check if the process firefox.exe exists (after it has been started by the start command).
If the process exists, it will go to the label :fullscreen,
else the batch will go the the label :timeout. Then, it will check again if the process firefox.exe exists and if not, it will go again to the label :fullscreen until the process exists.
Here is my batch:
#echo off
start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
:timeout
timeout /t 5
:fullscreen
nircmd sendkeypress F11
exit
How can I do this check ?
You can also use QUERY PROCESS:
#Echo Off
If Not Exist "%ProgramFiles(x86)%\Mozilla Firefox\firefox.exe" Exit/B
Start "" "%ProgramFiles(x86)%\Mozilla Firefox\firefox.exe"
:Loop
Timeout 5 /NoBreak>Nul
QProcess firefox.exe>Nul 2>&1||GoTo :Loop
NirCmd SendKeyPress F11
I suggest for this task the batch file:
#echo off
start "" /max firefox.exe
if errorlevel 1 goto :EOF
set LoopCount=0
:WaitLoop
%SystemRoot%\System32\timeout.exe /T 5
%SystemRoot%\System32\tasklist.exe /FI "IMAGENAME eq firefox.exe" 2>nul | %SystemRoot%\System32\find.exe /I "firefox.exe" >nul
if not errorlevel 1 nircmd.exe sendkeypress F11 & goto :EOF
set /A LoopCount+=1
if not %LoopCount% == 6 goto WaitLoop
Let me explain the few command lines used here.
1. Starting Firefox
The command START being an internal command of cmd.exe interprets the first double quoted string as optional title for the console window. Therefore the command line
start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
results just in opening a new console window with the window title:
C:\Program Files (x86)\Mozilla Firefox\firefox.exe
For that reason "" is specified as first START argument to define an empty title. Firefox is a GUI application. So no console window is opened which means an empty window title is really enough.
The parameter /max would not be really necessary, but the goal is to get Firefox into full screen mode after starting. So why not starting it already maximized?
32-bit version of Firefox is by default installed in directory %ProgramFiles% on 32-bit Windows and in %ProgramFiles(x86)% on 64-bit Windows. But it is possible during the installation to install Firefox into any other folder. But Firefox installer is well coded and registers firefox.exe in Windows registry under key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
This is recommended by Microsoft as written in MSDN article Application Registration.
The command START searches also in Windows registry under this key for an executable specified as argument without path as explained in answer on Where is “START” searching for executables?
This is the reason for using just firefox.exe on START command line because that starts an installed Firefox independent on installation location.
START displays an appropriate message box if firefox.exe could not be started and exits in this case with a return code greater 0 (9059 in my test on one computer).
The help output on running if /? in a command prompt window explains how to evaluate the exit code of a previous command or application without usage of immediate or delayed environment variable expansion and therefore working anywhere in a batch file from MS-DOS (really!) to currently latest Windows 10.
The command line if errorlevel 1 goto :EOF means IF start failed to start firefox.exe indicated by an exit code greater or equal 1 THEN exit execution of this batch file. For details on exiting batch file execution see answer on Where does GOTO :EOF return to?
2. Checking for running Firefox
The command TASKLIST being an external command, i.e. a console application in system directory of Windows, outputs a list of running processes. This list can be already filtered by TASKLIST itself for a specific process as done in batch file with /FI "IMAGENAME eq firefox.exe".
But TASKLIST is designed for just printing a list of processes. It is not designed for checking if a specific process is running and returning the result to the calling process via exit code. TASKLIST always exits with 0.
But an error message is output to handle STDERR on using a filter and no process can be found in process list matching this filter. For that reason 2>nul is used to suppress this error message by redirecting it to device NUL. Read the Microsoft article about Using Command Redirection Operators for more information about redirection.
A simple method to get a simple false/true respectively 0/1 result on checking for running Firefox is filtering output of TASKLIST with external command FIND which exits with 0 if the string to find was indeed found or with 1 if the searched string could not be found in the text read in this case from STDIN. The output of FIND is of no interest and therefore suppressed with redirection to device NUL using >nul.
Instead of using TASKLIST and FIND it is also possible to use QPROCESS:
%SystemRoot%\System32\qprocess.exe firefox.exe >nul 2>&1
QPROCESS exits with exit code 1 if firefox.exe could not be found in list of running processes. Otherwise the exit code is 0 on firefox.exe is running.
3. Evaluating Firefox process checking result
if not errorlevel 1 nircmd.exe sendkeypress F11 & goto :EOF
The IF command checks if exit code of FIND is NOT greater or equal 1 which means if exit code is lower than 1. Command FIND exits never with a negative value. So if this condition is true then it is time to execute nircmd.exe to send key press F11 to application in foreground hopefully being Firefox (not guaranteed by this code) and exit batch file processing.
Otherwise the batch file should wait once again 5 seconds and then do the check again. This can very easily result in an endless running batch file in case of started Firefox is immediately closed by the user before the 5 seconds wait timed out. For that reason it is counted how often the wait loop is already executed. After 6 loop runs, or 30 seconds, it is really time to no longer wait for Firefox and exit the batch file.
4. Getting more information about used commands
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
find /?
if /?
qprocess /?
set /?
start /?
tasklist /?
timeout /?
And Single line with multiple commands using Windows batch file should be also read explaining operator & in addition to all other web pages referenced already above.
You can show a list of opened programs like this:
tasklist
To check if firefox exists:
EDIT: Code edited to show a fully working example
#echo off
start "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
goto :checkloop
:checkloop
tasklist|find "firefox.exe" > NUL
if %ERRORLEVEL% == 0 (
call :fullscreen
exit
) else (
call :timeout
goto :checkloop
)
:fullscreen
nircmd sendkeypress F11
goto :EOF
:timeout
timeout /t 5
goto :EOF

Command Line - Wait for a Process to Finish

I'm installing a set of drivers in an unattended script. One of the drivers (Intel USB3 Drivers) kicks off the Windows Driver Finder application ("drvinst.exe") after it's finished. Then, when the nVidia Drivers try to run, they cancel out because that Wizard is still running in the background.
My current solution is this, but it is not very elegant:
:INSTALLLAPTOP79
.\ELAN\Touchpad\Setup.exe /s /a /s
.\Intel\Chipset\Setup.exe -s -norestart
.\Intel\Graphics\Setup.exe -s
.\Intel\MEI\Setup.exe -s
.\Intel\USB3\Setup.exe -s
.\Realtek\Audio\Setup.exe /s
.\Realtek\CardReader\Setup.exe /s
TIMEOUT 180
.\nVidia\Graphics\Setup.exe -n -s
GOTO :INSTALLLAPTOPWIFI
Basically if a system is slower than "normal" it will fail as the 180 seconds isn't enough. I could just increase this value but that is messy to me.
I'm basically looking for a way to do a "check" to see if the "drvinst.exe" is still running and if so wait for a set period - then do the check again.
Any ideas?
It's not guaranteed to work (it depends on how the installers launch the driver-finder) but:
start /wait command...
may do the trick. Be aware that if the command to be executed contains spaces, and needs to be wrapped in double-quotes, you'll need:
start /wait "" "c:\program files\something\..."
otherwise it will take the command as the title of the command-prompt.
#ECHO OFF
SETLOCAL
notepad
:waitloop
TASKLIST /fi "imagename eq notepad.exe" >NUL
IF ERRORLEVEL 1 timeout /t 1 /n&GOTO waitloop
GOTO :EOF
Here's a simple method waiting for notepad.exe to close. Adapt as you will...
#ECHO OFF
SETLOCAL
notepad
:waitloop
TASKLIST |find "notepad.exe" >NUL
IF ERRORLEVEL 1 timeout /t 1 /n&GOTO waitloop
GOTO :EOF
should work also
This works for me in Windows 10 (1903). Caveat: if you use it for a process that is running multiple times, it waits for all of them to finish before continuing.
Based on this answer by #Magoo which didn't work for me, but put me on the right track.
#ECHO OFF
notepad.exe
REM For the OP's original problem, put drvinst.exe instead of notepad.exe (here and below)
:waitloop
TASKLIST |find /I "notepad.exe" >NUL
IF ERRORLEVEL 1 GOTO endloop
REM echo Notepad running. Waiting 1 second...
timeout /t 1 /nobreak>NUL
goto waitloop
:endloop
echo Done!
i dont know if this is the best way to do it, but i know it works 100%
I use call in my scripts when i need it to wait.
:INSTALLLAPTOP79
Call \ELAN\Touchpad\Setup.exe /s /a /s
Call \Intel\Chipset\Setup.exe -s -norestart
Call \Intel\Graphics\Setup.exe -s
Call \Intel\MEI\Setup.exe -s
Call \Intel\USB3\Setup.exe -s
Call \Realtek\Audio\Setup.exe /s
Call \Realtek\CardReader\Setup.exe /s
Call \nVidia\Graphics\Setup.exe -n -s
GOTO :INSTALLLAPTOPWIFI
Call will make the script wait until the exe that's being ran is finished.
Not sure what purpose the . before the \ serves but you may need it if its there for a reason.

Making command prompt wait

#call JBOSSbuildWar.bat > ..\logs\JBOSSbuildWar_out 2> ..\logs\JBOSSbuildWar_err
start cmd /c #call WeblogicbuildWar.bat > ..\logs\WeblogicbuildWar_out 2> ..\logs\WeblogicbuildWar_err
start cmd /c #call FEBAPortletWebWar.bat > ..\logs\FEBAPortletWebWar_out 2> ..\logs\FEBAPortletWebWar_err
start cmd /c #call buildStaticJBoss.bat > ..\logs\JBOSSFEBAStaticWar_out 2> ..\logs\JBOSSFEBAStaticWar_err
I have this set of batch files getting executed in order. I want to fork out this so that they execute in parallel. I have done that using start cmd /c. Now this will fork out new command prompt window for each of them. Assume there are some set of statements after this. I want to make sure they get executed only after all the forked batch files are finished. How to achieve this?
Lets say average time taken by each file is:
JBOSSbuildWar- 30 minutes
WeblogicbuildWar- 35 minutes
FEBAPortletWebWar- 30 minutes
buildStaticJBoss- 35 minutes
Since the main command prompt window has completed its task in 30 minutes, and the forked batch files needs another 5 minutes to complete, I want the main cmd to wait until the others are done. Kindly help.
there's multiple commands, you can choose what one to use,
Pause
Will pause cmd until the user presses any key.
Displays message, "Press any key to continue..."
I use a certain variation of this command called pause>nul.
What it does is pauses the .bat, but doesn't show a message, You just get a blank screen!
TIMEOUT
Multiple syntaxes, very useful command, use this one quite a bit.
Sample code: TIMEOUT 10
Can be bypassed by a key press
Pauses the execution of command by 10 seconds.
You can also structure it like this: TIMEOUT 10 /nobreak
Which does not allow the user to press a key to skip it, they must endure it!
Ping
Very nice one.
Syntax is like this: PING 1.1.1.1 -n 1 -w 60000 >NUL
Probably most complex of the three.
PING can be used to delay execution for a number of seconds.
Hope I helped!
-Logan
Easy way:
In your main batch,
del "%temp%\*.processfinished" >nul 2>nul
...
start ....whatever1.bat...
start ....whatever2.bat...
start ....whatever3.bat...
...
wait4all:
for /L %%a in (1,1,3) do if not exist "%temp%\%%a.processfinished" timeout /t 1 >nul &goto wait4all
:: continues here when all (3) processes have finished.
del "%temp%\*.processfinished" >nul 2>nul
Then in each of the (3) subsidiary .bat files, create a file "%temp%\x.processfinished" where x=1 for the first process, 2 for the second and so on.
When the sub-processes have started, the procedure waits until each has created its own ".processcompleted" file by checking whether any of the 3 is missing, if it it, timeout for 1 second and look again. Only if the 3 files are present will it continue.
In all probability, it would be best if the subsidiary processes could take an extra parameter (the name of this sub-process's "processfinished" file) rather than having a fixed number for each.
You could extend this, and use say the date and time to augment the filename so that this entire process could itself be run many times in parallel.
BTW - by starting the procedure with
#echo off
you can remove all of the leading #s (all that does is suppress the command-reporting for that one line.)
Also, start is happier as start "" ....., that is, with an empty window title in quotes as its first argument. This allows other arguments to be "quoted" as necessary - the very first "quoted" argument used is used as the "window title" for the process and is likely to be lost to the sub-process. Routinely assigning a dummy (empty if necessary) "window title" means you don't trip over this problem in the future.
You can add this timer function before each of the commands:
#call JBOSSbuildWar.bat > ..\logs\JBOSSbuildWar_out 2> ..\logs\JBOSSbuildWar_err
Timeout /t 60 /nobreak >nul
start cmd /c #call WeblogicbuildWar.bat > ..\logs\WeblogicbuildWar_out 2> ..\logs\WeblogicbuildWar_err
Timeout /t 60 /nobreak >nul
start cmd /c #call FEBAPortletWebWar.bat > ..\logs\FEBAPortletWebWar_out 2> ..\logs\FEBAPortletWebWar_err
Timeout /t 60 /nobreak >nul
start cmd /c #call buildStaticJBoss.bat > ..\logs\JBOSSFEBAStaticWar_out 2> ..\logs\JBOSSFEBAStaticWar_err
Ps: 60 stands for 1 minute, if you want 30 minutes, change it to 1800

Batch - Reboot computer if a batch file ends

Essentially we have 2 batch files, one which is the "wrapper" if you will, calling another batch file so it starts as /min (minimized). This batch file then ends once it has launched the 2nd batch file.
This contains a loop, which keeps spawning an RDP session after it is closed.
The problem is, if the user ALT-TABs and closes the batch, they are just left with an empty desktop (as we task kill explorer). Is there a way of force rebooting the machine if that batch loop ends?
Thanks!
There is a standard cmd command:
shutdown /r
Usage: shutdown [/i | /l | /s | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/f]
[/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]]
No args Display help. This is the same as typing /?.
/? Display help. This is the same as not typing any options.
/i Display the graphical user interface (GUI).
This must be the first option.
/l Log off. This cannot be used with /m or /d options.
/s Shutdown the computer.
/r Full shutdown and restart the computer.
/g Full shutdown and restart the computer. After the system is
rebooted, restart any registered applications.
/a Abort a system shutdown.
This can only be used during the time-out period.
/p Turn off the local computer with no time-out or warning.
Can be used with /d and /f options.
/h Hibernate the local computer.
Can be used with the /f option.
/hybrid Performs a shutdown of the computer and prepares it for fast startup.
Must be used with /s option.
/e Document the reason for an unexpected shutdown of a computer.
/o Go to the advanced boot options menu and restart the computer.
Must be used with /r option.
/m \\computer Specify the target computer.
/t xxx Set the time-out period before shutdown to xxx seconds.
The valid range is 0-315360000 (10 years), with a default of 30.
If the timeout period is greater than 0, the /f parameter is
implied.
/c "comment" Comment on the reason for the restart or shutdown.
Maximum of 512 characters allowed.
/f Force running applications to close without forewarning users.
The /f parameter is implied when a value greater than 0 is
specified for the /t parameter.
/d [p|u:]xx:yy Provide the reason for the restart or shutdown.
p indicates that the restart or shutdown is planned.
u indicates that the reason is user defined.
If neither p nor u is specified the restart or shutdown is
unplanned.
xx is the major reason number (positive integer less than 256).
yy is the minor reason number (positive integer less than 65536).
My suggestions:
Do you really need batch to be visible (minimized) or can it be hidden?
If it can be hidden, just use VBScript to launch it hidden:
With CreateObject("W"&"Script.Shell")
.Run "LongRun.bat", 0
End With
If you really need batch to be shown, you could make a hidden script which will wait for batch to terminate and reboot.
Step 1: Launch script hidden (Start.vbs):
Set WsShell = CreateObject("W"&"Script.Shell")
WsShell.Run "Hidden.vbs", 0
Step 2: Hidden.vbs will launch batch and wait it to return:
'This script is supposed to start hidden!
Set WsShell = CreateObject("W"&"Script.Shell")
WsShell.Run "LongRun.bat", 7, True
'WsShell.Run "REBOOT.EXE ..." 'Must remove comment and complete command line
MsgBox "Rebooting..."
Now LongRun.bat is running, Hidden.vbs also (but not visible).
If somehow LongRun.bat is terminated, Hidden.vbs will continue its execution and reboot.
(WScript.Shell.Run documentation)
EDIT: Notice "W"&"Script.Shell" is same as "WScript.Shell" but StackOverflow doesn't allow me to write it!

Resources