Batch compare timer result to a number - windows

I have a batch timer (saw it in a different stackOverFlow post) and I need to compare the elapsed time to a number in order to know when 10 seconds are pass, however, I'm getting an error when trying to compare the two.
What am I doing wrong?
#set /A _tic=%time:~0,2%*3600^
+%time:~3,1%*10*60^
+%time:~4,1%*60^
+%time:~6,1%*10^
+%time:~7,1% >nul
echo RUN-KILL-WATCHDOG-THE-SMART-WAY
SETLOCAL EnableExtensions
set EXE=python.exe
:RUNNERON
FOR /F "skip=1" %%x IN ('wmic process where "CommandLine Like '%%forking import main%%' and Caption='python.exe'" get caption') DO for /F "delims=" %%j in ("%%x") do (
echo The name of process who passed filter is: %%j Waiting for it to terminate...
IF %%j == %EXE% (
:: TOK
set /A _toc=%time:~0,2%*3600^
+%time:~3,1%*10*60^
+%time:~4,1%*60^
+%time:~6,1%*10^
+%time:~7,1% >nul
set /A _elapsed=%_toc%-%_tic
:: echo %_elapsed% seconds.
IF %_elapsed%==10 goto TIMEOUT :: EVERYTHING WORKS BUT THIS LINE
goto RUNNERON
) ELSE (
echo Entered "else" part - something went wrong.
)
)
echo Runner is done - killing watchdog process
taskkill /F /im "python.exe"
: TIMEOUT
echo TIMEOUT
pause
when I run it I get the error:
"goto was unexpected at this time."
What am I missing?
Thank you

Related

wmic terminate process not found

wmic process where name="abc.exe" call terminate
Sometimes I got the below error:
Description = Not Found
I suspect that this is because abc.exe is not running. Is this the case? If yes, is there a way to check if abc.exe is running before calling terminate?
Here is a batch example for killing any instances of Google Chrome using CommandLine with WMIC.
#echo off
Title BATCH Killing Program using CommandLine with WMIC
Set MyProgramPath=C:\Program Files\Google\Chrome\Application\chrome.exe
#for %%a in ("%MyProgramPath%") do set "MyProgramName=%%~nxa"
Set MyProgramPath=%MyProgramPath:\=\\%
set idx=0
:MAIN
cls
echo( Looking for any instances of "%MyProgramName%" ...
Set "Found="
SETLOCAL EnableDelayedExpansion
#for /f "Tokens=2 Delims==" %%a in ('wmic PROCESS where "CommandLine Like '%%%MyProgramPath%%%' And Name Like '%%%MyProgramName%%%'" get ProcessID /Value') do (
#for /f "delims=" %%b in ("%%a") do (
Set /a idx+=1
set "MyPID[!idx!]=%%~nb"
set "Found=True"
)
)
If /I [!Found!] EQU [True] (
echo( We found PID for "%MyProgramName%"
#for /l %%i in (1,1,!idx!) do echo( %%i - !MyPID[%%i]!
echo( Did you want to Kill this program "%MyProgramName%" [Y=YES]
Set /P "Answer="
IF /I [!Answer!] EQU [Y] (
#for /l %%i in (1,1,!idx!) do Taskkill /T /F /PID !MyPID[%%i]!
) else (
Endlocal
Timeout /T 1 /NoBreak>nul
Goto Main
)
) else (
Timeout /T 10 /NoBreak>nul
Goto Main
)

Arrange the pinging of multiple website in order with batch?

This is a batch that pings the servers of a game I play, so that I am able to find the best server for me.
Is there a way I can have it ping all the servers then list them in order from the slowest response to the highest?
#TITLE OSRS Ping Checker
#ECHO off
SET usaworlds=5,6,7,13,14,15,19,20,21,22,23,24,29,30,31,32,37,38,39,40,45,46,47,48,53,54,55,56,57,61,62,69,70,74,77,78,86,117
#ECHO ---------------------------------------------------
#ECHO USA
#ECHO ---------------------------------------------------
FOR %%i IN (%usaworlds%) DO (
Echo | SET /p=World %%i
FOR /F "tokens=5" %%a IN ('Ping oldschool%%i.runescape.com -n 1 ^| FIND "time="') DO Echo %%a
)
PAUSE
#ECHO off
setlocal enabledelayedexpansion
TITLE OSRS Ping Checker
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
del x.tmp 2>nul
SET usaworlds=5,6,7,13,14,15,19,20,21,22,23,24,29,30,31,32,37,38,39,40,45,46,47,48,53,54,55,56,57,61,62,69,70,74,77,78,86,117
ECHO ---------------------------------------------------
ECHO USA
ECHO ---------------------------------------------------
FOR %%i IN (%usaworlds%) DO (
<nul set /p "=checking World %%i !CR!"
FOR /F "tokens=5" %%a IN ('Ping oldschool%%i.runescape.com -n 1 ^| FIND "TTL="') DO (
for /f "tokens=2 delims==" %%b in ("%%a") do (
set tim=00000%%b
set tim=!tim:~-7,-2!
)
)
echo !tim! World %%i>>x.tmp
)
for /f "tokens=3" %%c in ('sort /r x.tmp') do set fastest=%%c
echo fastest response from World %fastest%
PAUSE
Note: the time of a one-time ping isn't reliable (check the different times with ping -t) and so this approach may give you false results. better check "Average" with ping -n 5 or even higher, but that will of course decrease the performance of the script.
To make it faster and more reliable using the average times, you can run the pings in parallel (I have used that method years ago in another context)
#ECHO off
setlocal
TITLE OSRS Ping Checker
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
del %temp%\x.tmp 2>nul
SET usaworlds=wrgl,5,6,7,13,14,15,19,20,21,22,23,24,29,30,31,32,37,38,39,40,45,46,47,48,53,54,55,56,57,61,62,69,70,74,77,78,86,117
#ECHO ---------------------------------------------------
#ECHO USA
#ECHO ---------------------------------------------------
FOR %%i IN (%usaworlds%) DO (
start /min "Pinging" cmd /v:on /c "(FOR /F "tokens=9 delims= " %%a IN ('Ping oldschool%%i.runescape.com -n 5^|findstr /e "ms"') do set avrg= %%a)& >> %temp%\x.tmp echo ^!avrg:~-7,-2^!" World %%i
)
:wait
timeout 1 >nul
tasklist /FI "WINDOWTITLE eq Pinging" |find ".exe" >nul && goto :wait
for /f "tokens=3" %%c in ('sort /r %temp%\x.tmp') do set fastest=%%c
echo fastest response from World %fastest%
PAUSE
Using start /min instead of start /b does keep your screen clean in case of errors (makes it a bit slower, but you won't notice it)
Since there are many hosts to check/ping, sequencial processing lasts for a quite long time, particularly when following Stephan's recommendation of using more than one echo requests and taking the average reply time.
So I suggest to use a different approach and let the ping requests happen in simultaneous processes:
#title OSRS Ping Checker
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ARG=%~1" & if defined _ARG shift /1 & goto :DO_PING & ^
rem // (jump to label `DO_LOOP` in case arguments are provided)
set "_USAWORLDS=5,6,7,13,14,15,19,20,21,22,23,24,29,30,31,32,37,38,39,40,45,46,47,48,53,54,55,56,57,61,62,69,70,74,77,78,86,117"
set "_ECHOREQUS=10" & rem // (number of echo requests to send per host)
set "_TEMPFILEB=%TEMP%\%~n0_%RANDOM%" & rem // (path and base name of temporary files)
set "_FINALFILE=%~dpn0.txt" & rem // (path and full name of return file)
rem // Process items in sub-routine but in parallel processes:
for %%I in (%_USAWORLDS%) do (
rem // Redirect output of every process to individual temporary file:
> "%_TEMPFILEB%_%%~I.tmp" start /B "" cmd /C "%~f0" :DO_PING %%~I %_ECHOREQUS%
)
rem /* Wait until all temporary files are write-accessible, meaning that
rem all the parallel processes have been completed/terminated: */
:POLL
for %%I in (%_USAWORLDS%) do (
rem // Try appending nothing to check for write-access:
2> nul (>> "%_TEMPFILEB%_%%~I.tmp" rem/) || (
rem // Wait a bit to not overload the processor:
> nul timeout /T 1 /NOBREAK
goto :POLL
)
)
rem // Combine all individual temporary files into one:
> nul copy /Y "%_TEMPFILEB%_*.tmp" "%_TEMPFILEB%.tmp" /B
rem // Sort data as desired (alphabetic sorting):
sort /R "%_TEMPFILEB%.tmp" /O "%_TEMPFILEB%.tmp"
rem // Create return file, write header:
> "%_FINALFILE%" echo ms host
rem // Append sorted data to return file:
> nul copy /Y "%_FINALFILE%" + "%_TEMPFILEB%.tmp" "%_FINALFILE%" /B
rem // Clean up temporary files:
del "%_TEMPFILEB%_*.tmp" "%_TEMPFILEB%.tmp"
endlocal
exit /B
:DO_PING
rem // Build host URL to ping, set number of echo requests to send:
set "URL=oldschool%~1.runescape.com"
set /A "NUM=%~2"
rem /* Perform ping and capture last line of response, which should contain
rem the average reply time: */
set "STR="
for /F "delims=" %%P in ('2^> nul ping "%URL%" -n %NUM%') do set "STR=%%P"
rem // Check whether last line of response contains average reply time:
if not defined STR exit /B
set "AVG=%STR:*Average =%"
set "AVG=%AVG:~1%"
if "%AVG%"=="%STR%" exit /B
rem /* Convert average reply time to pure left-zero-padded number; the padding
rem is intended to simplify the later (purely alphabetic) sorting: */
set /A "AVG=AVG"
set "AVG=000000%AVG%"
rem // Return average reply time together with respective host URL:
echo %AVG:~-6% "%URL%"
exit /B

Manipulate cmd ping color based on time

My internet is not always working properly and I'd like to check the quality based on the cmd windows tool. I believe it's a task simple enough for it to handle.
I've begun by making a shortcut so I can have easy access to the command:
C:\Windows\System32\PING.EXE 8.8.8.8 -t
Now I was trying to transform the cmd ping command into a visually responsive one based on the output. I'd like to make the color change according to the time response.
After looking and not finding anything related, I believe it's either impossible or no one has ever tried.
Thank you very much :)
PD: (In case there was anything unclear just ask and I'll gladly answer)
Based on Magoo's post, I wrote this little batch program.
It asks for the target, the number of requests to make, the max time allowed and the time between requests and then prints in red if the request is over the time max, otherwise it sums the number of requests. It includes timestamp to be more accurate.
Copy and paste in a text file and name it with extension ".bat" (But don't name it "ping.bat" otherwise the program will enter in an infinite loop).
REM CMD PING TOOL
REM By Daweb
REM https://stackoverflow.com/users/3779294/daweb
#ECHO OFF
REM Needed for Line colored
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=1,2 delims=#" %%a IN ('"PROMPT #$H#$E# & echo on & for %%b in (1) do rem"') do (
SET "DEL=%%a"
)
for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
ECHO *****************
ECHO * CMD PING TOOL *
ECHO *****************
REM Start
:start
ECHO.
ECHO Set yours values
REM SET Target
SET /p hostInput=" - Target (ip or hostname): "
If "%hostInput%"=="" ECHO.&GOTO start
REM SET loops
SET /p loopsInput=" - Requests number: "
SET /a loops=loopsInput
REM SET time limit
SET /p maxmsInput=" - Maximum Time Limit (ms): "
SET /a maxms=maxmsInput
REM Value used for sleep between loops
SET /p sleepInput=" - Delay between requests (s): "
SET /a sleepDelay=sleepInput+1
REM Variables
SET displayText=""
SET /a countRequestsOk=0
SET /a countRequestsKo=0
SET /a totalRequests=0
SET /a maxTime=0
ECHO.
ECHO START at %TIME% [target: %hostInput%, requests: %loops%, time limit: %maxms% ms, delay: %sleepInput% s]
ECHO.
REM Loop
:loop
REM Set time
FOR /f "tokens=1-3 delims=/:" %%a IN ("%TIME%") DO (SET mytime=%%ah%%bm%%cs)
REM Get ping value
FOR /f "tokens=3delims==" %%a IN ('PING -n 1 %hostInput%') DO FOR /f "delims=m" %%b IN ("%%a") DO (
SET /a timems=%%b
SET /a totalRequests+=1
REM Check result
IF !timems! GTR %maxms% ( GOTO failed ) ELSE ( GOTO success )
)
REM Request success
:success
SET /a countRequestsOk+=1
IF !timems! GTR !maxTime! ( SET /a maxTime=timems )
<nul set /P "=!countRequestsOk! requests [Max !maxTime! ms]!CR!"
GOTO next
REM Request failed
:failed
IF !countRequestsOk! GTR 0 ECHO.
SET /a countRequestsOk=0
SET /a countRequestsKo+=1
SET displayText=" %mytime% - !timems!ms"
CALL :ColorText 0c !displayText!
GOTO next
REM Next loop
:next
REM Sleep a little bit
IF %sleepDelay% GTR 1 ( ping -n %sleepDelay% localhost > nul )
REM Check continue
SET /a loops-=1
IF %loops% gtr 0 GOTO loop
REM Display result
IF !countRequestsOk! GTR 0 ECHO.
ECHO.
ECHO STOP at %TIME%
ECHO.
if !countRequestsKo! GTR 0 (
SET displayText="FAILED - !countRequestsKo! requests over %maxms% ms on !totalRequests! requests in total"
CALL :ColorText 0c !displayText!
) ELSE (
SET displayText="SUCCESS - No request over %maxms% ms on !totalRequests! requests in total"
CALL :ColorText 02 !displayText!
)
REM Ask if restart
ECHO.&ECHO *********************
SET /p restartInput="Do it again ? (Y/N): "
If "%restartInput%"=="" ECHO *********************&GOTO start
If /I "%restartInput%"=="y" ECHO *********************&GOTO start
If /I "%restartInput%"=="n" ECHO *********************&GOTO end
REM End
:end
PAUSE
GOTO :EOF
REM Line color
:ColorText
ECHO off
ECHO %DEL% > "%~2"
FINDSTR /v /a:%1 /R "^$" "%~2" NUL
DEL "%~2" > NUL 2>&1
#ECHO OFF
SETLOCAL
SET loops=10
:loop
FOR /f "tokens=3delims==" %%a IN ('PING 8.8.8.8 -n 1') DO FOR /f "delims=m" %%b IN ("%%a") DO ECHO %%b&COLOR %%b&GOTO cchgd
:cchgd
PAUSE
SET /a loops-=1
IF %loops% gtr 0 GOTO loop
COLOR
GOTO :EOF
A simple demonstration - repeats the ping 10 times, changing colours depending on the response. Manipulate to do as you wish...
I am not sure that I know what the desired output should be, but this will output GREEN text for response times 0-39 ms, YELLOW for 40-79 ms, and RED for 80+ ms.
Run this from a cmd.exe prompt using the following command or put it into a .bat file script. Change the directory to the location where the Get-PingColor.ps1 file is landed.
powershell -NoLogo -NoProfile -File "%USERPROFILE%\bin\Get-PingColor.ps1"
=== Get-PingColor.ps1
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string[]]$ComputerNames
,[Parameter(Mandatory=$false)]
[int]$Count = 4
,[Parameter(Mandatory=$false)]
[int]$SpeedMinimumSlow = 80
,[Parameter(Mandatory=$false)]
[int]$SpeedMinimumMedium = 40
)
foreach ($ComputerName in $ComputerNames) {
$Pings = Test-Connection -ComputerName $ComputerName -Count $Count
$Average = ($Pings | Measure-Object -Property responsetime -Average).Average
$ForegroundColor = 'Green'
if ($Average -ge $SpeedMinimumSlow) { $ForegroundColor = 'Red'}
else { if ($Average -ge $SpeedMinimumMedium) { $ForegroundColor = 'Yellow' }}
Write-Host -ForegroundColor $ForegroundColor -BackgroundColor 'Black' "$ComputerName $Average ms"
}
=== Execution examples
I am loathe to put images into a post, but I do not see a way to produce color on SO.

'if errorlevel' statement when in 'for findstr' loop

I have been unsuccessful getting the following to work. Everything works until I try to get the results of the 'findstr' in the 'for' loop. Maybe there is a better way of doing this: look for %subnet% in the masters.csv file. If it finds it, set the MSS variable to the resulting value from the 'for'. If it does not find a value, it will assign a static value (orphan). Thanks in advance for any help!!
for /f "tokens=1-2 delims=:" %%a in ('ipconfig^|find "IPv4"') do set ip=%%b
set ip=%ip:~1%
echo %ip% > ipaddress.txt
pause
for /F "tokens=1-3 delims=." %%a in ("%ip%") do set FirstThreeOctets=%%a.%%b.%%c
#REM echo First three: %FirstThreeOctets%
#echo off
setlocal
set subnet=%FirstThreeOctets%
echo %subnet%
for /f "tokens=2 delims=," %%A in ('findstr /r "^%subnet%," "\\server\APPS\appname\updates\masters.csv"') do goto OrphanCheck
#REM if errorlevel ==1 goto Orphan do set MSS=%%A
#REM echo %MSS%
#REM goto 64installcheck
:OrphanCheck
if errorlevel==1 goto Orphan
Goto NoOrphan
:NoOrphan
set MSS=%%A
Goto 64installcheck
:Orphan
set MSS=ORPHAN
echo %MSS%
pause
When you run
for /f "tokens=2 delims=," %%A in (
'findstr /r "^%subnet%," "\\server\APPS\appname\updates\masters.csv"'
) do goto OrphanCheck
two things can happen.
If findstr does not find the string, code in for loop is not executed and the next line is reached, but this line does not have access to the errorlevel generated by the findstr, it sees the errorlevel (?) of the for command.
If findstr finds the string, the goto is executed but the same scenario happens.
When the line that checks the error level is reached, another problem raises
if errorlevel==1
is a valid construct, but it does not do what it seams. It is testing if the string errorlevel is equal to the string 1. The correct sintax should be
if errorlevel 1 ....
or
if %errorlevel%==1
but as indicated, when the line is reached the errorlevel will not reflect the error of the findstr command.
And three lines later the next error.
set MSS=%%A
Once the for command has ended, its replaceable parameter does not have any value.
For a simplified version of your code
for /f "tokens=3-6 delims=.: " %%a in ('ipconfig ^| find "IPv4"') do (
set "ip=%%a.%%b.%%c.%%d"
set "subnet=%%a.%%b.%%c"
)
>"ipaddress.txt" echo %ip%
for /f "tokens=2 delims=," %%a in (
'findstr /b /c:"%subnet%," "\\server\APPS\appname\updates\masters.csv"'
) do (
set "MSS=%%a"
goto 64installcheck
)
set "MSS=ORPHAN"
echo %MSS%
pause

Return variable through start command

I am looking for a way to get a value return from a start-command launched batch script. Let me explain:
I need to take advantage of multiprocessing by launching multiple sub-batch scripts simultaneously from a main batch script, then retrieve every sub batch file return value when they're done.
I've been using return variables with the call-command as very well explained by dbenham.
That solution does not allow multithreading, since sub-batch scripts are run one after the other.
Using the start-command allows multiple running batch scripts, but values are not returned to my main script because apparently the start-command creates a whole new variable context.
Does anybody have a solution/workaround to return values from the sub-scripts to the main script ?
Below is a model of what I need:
mainScript.bat
#echo off
setlocal
set "retval1=0"
set "retval2=0"
REM run two scripts in parallel:
start "" subscript1.bat arg1 retval1
start "" subscript2.bat arg1 retval2
REM wait for returned value
:waiting
call :sleep 1
set /a "DONE=1"
if %retval1% equ 0 set "DONE=0"
if %retval2% equ 0 set "DONE=0"
if %DONE% equ 0 goto :waiting
echo returned values are %retval1% %retval2%
exit /b
subscript1.bat
#echo off
setlocal
set "arg1=%~1"
set "retval1=%~1"
REM do some stuff...
REM return value
(endlocal
set "%retval1%=%foo%"
)
exit /b
Can't see any alternative to writing your return values to files, so
main
#ECHO OFF
SETLOCAL
for %%a in (1 2) do (
del "%temp%\retval%%a" 2>nul
)
start /min "" q225220791.bat arg1 retval1
choice /t 1 /d y >nul
start /min "" q225220791.bat arg1 retval2
:waiting
choice /t 1 /d y >nul
ECHO wait...%retval1%...%retval2%
if not exist "%temp%\retval1" goto waiting
if not exist "%temp%\retval2" goto waiting
for %%a in (1 2) do (
for /f "usebackqdelims=" %%i in ("%temp%\retval%%a") do set "retval%%a=%%i"
)
for %%a in (1 2) do (
del "%temp%\retval%%a" 2>nul
)
echo returned values are %retval1% %retval2%
GOTO :EOF
q225220791.bat
#ECHO OFF
SETLOCAL
:: wait a random time 2..10 sec.
SET /a timeout=%RANDOM% %% 8 + 2
choice /t %timeout% /d y >nul
:: return a random result 12..20
SET /a foo=%RANDOM% %% 8 + 12
>"%temp%\%2" echo %foo%
ENDLOCAL
exit
Relying on the value of the second parameter to the sub-process to set the tempfile name. I've changed the names of the batches to suit my system.
Not sure if this is even practical, but just testing to avoid the temporary file. So looking for a place in child process that can be readed from parent process i decided to use the window title.
task.cmd
#echo off
setlocal
rem Retrieve task information and set window title
set "taskID=%~1"
title [task];%taskID%;working;
rem Retrieve the rest of parameters. For this sample, a random value
set /a "timeToWait=%~2 %% 30"
rem Simulate command processing
timeout /t %timeToWait%
rem Calculate a return value for this task
for /f "tokens=1-10 delims=,.:/ " %%a in ("%date%%time%_%~2") do set "returnValue=%%a%%b%%c%%d%%e%%f%%g%%h%%i%%j"
rem Signal the end of the task
title [task];%taskID%;ended; my return value is %returnValue% ;
rem Wait for master to end this tasks
cls
echo Waiting for master....
waitfor %taskID%
rem Cleanup
endlocal
master.cmd
#echo off
setlocal enableextensions enabledelayedexpansion
rem Configure tasks
set "taskPrefix=myTSK"
set "numTasks=5"
rem Start tasks
for /l %%a in (1 1 %numTasks%) do (
set "return[%taskPrefix%%%a]=unknown"
start "[task];%taskPrefix%%%a;working;" cmd /c "task.cmd %taskPrefix%%%a !random!"
)
rem Wait for tasks to start
timeout /t 2 > nul
rem Wait for tasks to end. Get the list of cmd.exe windows with window title
rem to see the state of the task
rem Tasks in working state indicate master needs to keep working
rem Tasks in ended state have the return value in the window title and are
rem waiting for the master to retrieve the value and end them
:wait
set "keepWaiting="
for /f "tokens=9 delims=," %%a in ('tasklist /fi "imagename eq cmd.exe" /fo csv /v ^| findstr /l /c:"[task];%taskPrefix%"'
) do for /f "tokens=2-4 delims=;" %%b in ("%%a") do (
if "%%c"=="working" (
set "keepWaiting=1"
) else if "%%c"=="ended" (
set "return[%%b]=%%d"
start "" /min waitfor.exe /si %%b
)
)
rem If any task has been found in working state, keep waiting
if defined keepWaiting (
echo %time% : waiting ...
timeout /t 5 > nul
goto wait
)
rem All tasks have ended. Show return values
for /l %%a in (1 1 %numTasks%) do (
echo task #%%a ended with exit value :[!return[%taskPrefix%%%a]!]
)
endlocal
In this sample, the task waits for master using waitfor command. In XP this is not available, and can be replaced with just a pause, and from master.cmd the waiting loop must be modified to include the processID token in the tasklist processing, so the waiting task can be closed with taskkill.

Resources