Batch file - loop ping - output to file hosts that are up - batch-file

I would like to make a .bat file that will do a for loop like below:
#echo off
FOR /L %%G IN (1, 1, 69) DO (
ping -n 1 192.168.%%G.3
ping -n 1 192.168.%%G.4
)
Then look through the output and send only the IPs that replied successfully to the ping to a txt file. Is this possible with a CMD batch file?

#ECHO OFF
SET output=%USERPROFILE%\output.txt
IF EXIST "%output%" DEL "%output%"
FOR /L %%G IN (1, 1, 69) DO (
CALL :ping 192.168.%%G.3
CALL :ping 192.168.%%G.4
)
GOTO :EOF
:ping
ping -n 1 %1 >NUL && ECHO %1>>"%output%"
Basically, you use && to add the command that is only executed if the previous command (the one before the &&) completed successfully (technically speaking, returned the exit code of 0).
There's a similar approach for the opposite case. If you want to perform some actions on the unsuccessful result of a command, you put || after it and then the command implementing your action.
EDIT
One note about ping. Sometimes you get a notification from the router that the host is not accessible. In this case ping still exits with 0 code ('successful'), because it does get a reply, even if it's from the router and not from the actual host.
If that can be the case with your hosts and you don't want to have such false positives in the output file, you'll have to parse the output of ping for some keywords indicating whether the pinging was successful indeed. So far you can rely on the lines showing the aggregate stats: they only appear if the reply was from the intended host.
So, here's the alternative approach:
#ECHO OFF
SET output=%USERPROFILE%\output.txt
IF EXIST "%output%" DEL "%output%"
FOR /L %%G IN (1, 1, 69) DO (
CALL :ping 192.168.%%G.3
CALL :ping 192.168.%%G.4
)
GOTO :EOF
:ping
ping -n 1 %1 | find "Approximate round trip" >NUL && ECHO %1>>"%output%"
EDIT 2
Changed both solutions to use subroutine call in order to avoid premature expansion of %ip% inside the for loop. (Could also be fixed by enabling delayed expansion instead.)
Also quoted %output% everywhere.

#echo off
:A
FOR /L %%G IN (1, 1, 69) DO (
ping -n 1 192.168.%%G.3
ping -n 1 192.168.%%G.4
)
:GoTo

Related

Trying to ping a few devices using Batch arrays fails to resolve correctly

I am trying to make a batch file to quickly ping a number of devices to make sure they are all still on the network. If I type the commands in by hand, it seems give the expected output once, but doesn't seem to loop through the other iterations. Putting them in a batch file and running it somehow messes with my ability to call a variable. The IP just comes up as "i"
Is there something I'm missing? Thanks for the help.
set Device[0].Name=PC1
Set Device[0].IP=192.168.1.1
set Device[1].Name=PC2
Set Device[1].IP=192.168.1.2
set Device[2].Name=PC3
Set Device[2].IP=192.168.1.3
set _filepath=%userprofile%
echo %date% %time% > %_filepath%
SET /A i=0
:loop
IF %i%==3 GOTO END
call ping -n 1 %IDF[%i%].IP% | find "TTL=" >nul
if errorlevel 1 (
call echo %IDF[%i%].Name% IS OFFLINE >> %_filepath%
) else (
call echo %IDF[%i%].Name% Online >> %_filepath%
)
SET /A i=%i%+1
GOTO :loop
:END
In place of set /a i=0 onwards,
for /L %%s in (0,1,2) do (
CALL ping -n 1 %%Device[%%s].IP%% | find "TTL=" >nul
if errorlevel 1 (
CALL echo %%Device[%%s].Name%% IS OFFLINE >> %_filepath%
) else (
CALL echo %%Device[%%s].Name%% Online >> %_filepath%
)
)
The for /L (start,step,end) command can then be easily altered to process an extended list without using a goto
Noting that I severely suspect your setting of _filepath since it appears to be assigned a directoryname, not a filename
Also, use set "var1=data" for setting values - this avoids problems caused by trailing spaces. In comparisons, use if "thing1" == "thing2" ... to avoid problems caused by spaces in thing1/2.

How to play sound if phone connects to network?

I try to write a little batch script. It should play a sound if my phone joins my network.
#echo off
:A
ping -n 1 xxx.xxx.xxx.xx | findstr TTL && start airsiren.wav
goto A
The problem is now that if the phone is detected, it repeatedly starts the sound. But it's supposed to just play once.
Does anyone know a simple fix? Maybe with an IF condition?
I haven't been doing much with batch, but I think I got some basic knowledge.
I suggest following code:
#echo off
set "LastExitCode=1"
:Loop
%SystemRoot%\System32\ping.exe -n 1 xxx.xxx.xxx.xx | %SystemRoot%\System32\find.exe /C "TTL" >nul
if not %ErrorLevel% == %LastExitCode% set "LastExitCode=%ErrorLevel%" & if %ErrorLevel% == 0 start "Play sound" airsiren.wav
%SystemRoot%\System32\timeout.exe /T 5 /NOBREAK
if not errorlevel 1 goto Loop
PING outputs a line with TTL if there is a response on echo request and exits usually with value 0 on receiving a response and with 1 on getting no response. But PING does not always exit with 0 on a positive response which is the reason for using FIND.
FIND processes the output of PING and searches for lines containing the string TTL. FIND exits with value 0 on finding at least one line with TTL and otherwise with 1 for indicating no line found containing the search string. The output of FIND to handle STDOUT is of no interest and therefore reduced to a minimum by using option /C and redirected to device NUL.
Now the exit code of FIND is compared with an environment variable which holds last exit value of FIND initialized with value 1.
On current exit code being equal last exit code, there is no change in availability of the pinged device on network and therefore nothing to do.
Otherwise on a difference the current exit code is assigned to the environment variable for next loop run and current exit code is compared with value 0. If this second condition is true the pinged device sent the first time a positive response on echo request by PING. In this case the sound is played.
There is nothing else done on pinged device not available anymore on network, i.e. the exit code changes from 0 to 1.
Then a delay of 5 seconds is started using TIMEOUT with giving the user to break it with Ctrl+C. This reduces the processor core usage giving Windows the possibility to use the processor core for other processes and also reduces network usage when the pinged device is available at the moment on network. And of course the pinged device does not need anymore to permanently response on echo requests.
A jump to label Loop is done if TIMEOUT exited normally without a user break. Otherwise on user pressing Ctrl+C the batch file processing also ends.
TIMEOUT with parameter /NOBREAK requires Windows 7 or a later Windows version.
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 /?
goto /?
if /?
ping /?
set /?
start /?
timeout /?
See also single line with multiple commands using Windows batch file for an explanation of operator & and meaning of if not errorlevel 1.
This can be fixed very easily using %errorlevel% and an IF statement.
Original script by Jelle Geerts.
#ECHO OFF
:Search
ping -n 1 "xxx.xxx.xxx.xx" | findstr /r /c:"[0-9] *ms"
if %errorlevel% == 0 (
echo Device was found!
start airsiren.wav
pause.
) else (
goto Search
)
My solution:
#echo off &:: modem_tester_xp+.bat
REM original https://www.elektroda.pl/rtvforum/topic2917839.html
setlocal EnableDelayedExpansion
rem set connection name (for newer than Win XP) from Network Connections (preferred name doesn't have space)
set _connection_name=internet
rem make file which close this script
echo #echo.^>"%~dpn0.exit"^&#del /q "%%~f0">"%~dp0close_%~nx0"
for /f "tokens=2-4 delims==." %%a in ('wmic os get Version /value ^|find "="') do if "%%~c" neq "" set "_system_version=%%~a.%%~b"
set "_con_ip="
set "_my_ip.last="
:start
::-n (seconds+1)
ping 127.0.0.1 >nul -n 3
set "_my_ip="
if not defined _con_ip call :get_con_ip "%_connection_name%"
if defined _con_ip for /f "tokens=3-5 delims= " %%p in ('route print ^|find " 0.0.0.0 "') do if "%%~r" neq "" if /i "%%~p"=="%_con_ip%" ( set "_my_ip=%%~p" ) else if /i "%%~q"=="%_con_ip%" set "_my_ip=%%~q"
rem if connection lost clean variable _my_ip.last
if not defined _my_ip (
set "_con_ip="
set "_my_ip.last="
) else if /i "%_my_ip%" neq "%_my_ip.last%" (
rem remember last connection addres
set "_my_ip.last=%_my_ip%"
call :2run
)
if not exist "%~dpn0.exit" goto start
del /q "%~dpn0.exit"
endlocal
goto :eof
:get_con_ip &::ConnectionName:return variable _con_ip
if "%_system_version%"=="5.1" (
rem XP find modem address
for /f "tokens=2 delims== " %%a in ('netsh diag show gateway WAN* ^|find "." ^|find "="') do if "!_con_ip!"=="" set "_con_ip=%%~a"
) else (
rem if newer works like win7, if not: if "%_system_version%"=="6.1" (rem Windows 7
if "%~1" neq "" for /f "tokens=1,4* delims= " %%n in ('netsh interface ipv4 show interfaces ^|find /i "%~1"') do if "!_con_ip!"=="" if /i "%%~p"=="%~1" for /f "tokens=1* delims=:" %%i in ('netsh interface ipv4 show addresses %%~n ^|find "." ^|find /i "ip"') do if "!_con_ip!"=="" set "_con_ip=%%~j"
if "!_con_ip!" neq "" set "_con_ip=!_con_ip: =!"
)
goto :eof
:2run
rem run external
rem start "modem started" /min /b cmd /c "echo %date% %time% '%_my_ip%'&pause"
start airsiren.wav
There are two problems with your code
Your code will unconditionally goes to the beginning even after the phone is connected, so it repeats playing the sound. You could use ... && (start airsiren.wav & goto :EOF) to terminate the batch file or use another label other than :EOF to do something else. But this doesn't give you the option to keep monitoring the phone for disconnection and re-connection.
You have to check the setting of the default media player (Typically Windows Media Player) and make sure that it is not set to continuously loop or repeat the media. Also it is overkill and somewhat inconvenient to launch a full fledged media player just for playing back a short notification sound, and usually you have to close the media player afterwards.
So this is the code I propose which solves the above mentioned obstacles by providing the option to continuously monitor the phone's connection status and also provide a more programmatic way to play the notification sound in a self contained player by using a hybrid BAT/JSCript solution.
#if (#Code)==(#BatchScript) /* Hybrid BAT/JScript line */
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set #PlaySound=start "" /b cscript //nologo //e:JScript "%~f0"
set "SoundFile.Connect=%SystemRoot%\media\ringout.wav"
set "SoundFile.Disconnect=?"
set "GenFail.Localized.Text=General failure"
:: set to 0 to disable continuous connection monitoring
set "ContinuousMonitoring=1"
set "PhoneIP=xxx.xxx.xxx.xxx"
set "Timeout=3000"
setlocal EnableDelayedExpansion
set "CheckGeneralFailure=1"
echo [%TIME%] Waiting for connection...
:WaitForConnection
ping -n 1 %PhoneIP% -w %Timeout% | findstr "TTL" >nul && (
echo [!TIME!] Phone Connected.
!#PlaySound! "!SoundFile.Connect!"
if %ContinuousMonitoring% NEQ 0 goto :MonitorConnection
goto :EOF
) || (
if !CheckGeneralFailure! NEQ 0 (
ping -n 1 %PhoneIP% -w 100 | findstr /i /c:"%GenFail.Localized.Text%" >nul && (
ping -n 1 -w %Timeout% 127.255.255.255 >nul
(call,) %= Set errorlevel to 0 =%
) || set "CheckGeneralFailure=0"
)
goto :WaitForConnection
)
:MonitorConnection
ping -n 1 %PhoneIP% | findstr "TTL" >nul && (
ping -n 1 -w %Timeout% 127.255.255.255 >nul
goto :MonitorConnection
) || (
echo [!TIME!] Phone Disconnected.
echo [!TIME!] Waiting for connection...
set "CheckGeneralFailure=1"
REM Play another sound for disconnect?
goto :WaitForConnection
)
goto :EOF
/*** End of batch code ***/
#end
/*** JScript Sound Player ***/
var wmpps = {
Undefined : 0,
Stopped : 1,
Paused : 2,
Playing : 3,
ScanForward : 4,
ScanReverse : 5,
Buffering : 6,
Waiting : 7,
MediaEnded : 8,
Transitioning : 9,
Ready : 10,
Reconnecting : 11,
Last : 12
};
var SoundFile;
if (WScript.Arguments.length) SoundFile = WScript.Arguments(0);
var WaitCount = 0;
var objPlayer = new ActiveXObject("WMPlayer.OCX.7");
with(objPlayer) {
URL = SoundFile;
settings.volume = 100;
settings.setMode("loop", false);
controls.play();
while(playState == wmpps.Transitioning) {
WaitCount+=1;
if (WaitCount > 200) break;
WScript.Sleep(10);
}
if (playState == wmpps.Playing) {
while(playState != wmpps.Stopped) WScript.Sleep(1000);
}
close();
}

Better way to use findstr to get packet loss, batch

Looking to use findstr to get it to find "0% loss" after a ping command.
Perhaps an array of anything up to "50% loss".
This is for checking and ensuring a connection to the internet is 100% established before launching something online.
Currently it's structured:
ping %ip% -n 3 -w 3000 | findstr "0% loss"
pause
goto Starting
It's currently ignoring findstr and no matter what it refuses to find what I'm looking for
Ideally it would flow like:
ping %ip% -n 3 -w 3000 | findstr "0% loss" || goto Echo
pause
goto Starting
:echo
Could not find "0% loss"
pause
And I have tried that, it will go to echo, but even with 100% connection so it's clearly just not operating how I'd like it to.
Is there a better way to find % packet loss?
Or
Is there a better way to test internet connection, given ping doesn't work when a device is totally offline.
The search string you are looking for is too broad. When you check findstr for "0% loss", you are inadvertently picking up "100% loss" as well. Fortunately, ping puts the packet loss in parentheses, so you can simply include the open parenthesis in the search string.
#echo off
title Restart
color 0A
cls
:start
Cls
set ip=www.google.com
:Pingcheck
echo Checking ping..
timeout /t 3
ping %ip% -n 5 -w 3000 | findstr /C:"(0% loss" || goto Loss
pause
:NoLoss
echo We found 0 packet loss, at %ip% on %date% at %time%
pause
goto start
:Loss
echo We found some packet loss.
pause
I've also changed the name of the :Echo label because echo is already a command and having it also be a label would be confusing.
You can also check ping status with wmi. The advantage to this method is that it'll goto :fail on the first failure, and not continue its lost cause of completing 5 ping attempts, while also providing a simple way to preserve the average response time. It uses set /a to check whether the result of the wmi query contains a numeric value. If it does, pass. If not, fail.
#echo off & setlocal
set "host=www.google.com"
echo Pinging %host%...
for /L %%I in (1,1,5) do (
for /f "delims=" %%x in (
'wmic path win32_pingstatus where "address='%host%' and timeout=3000"^
get ResponseTime /value ^| find "="'
) do (
2>NUL set /a "%%x, avg += ResponseTime" || goto fail
)
)
set /a "avg /= 5"
echo 0%% packet loss. Woo. Average response time was %avg%ms.
exit /b
:fail
echo Aw snap. Packet loss.

Batch to pattern matching in a loop

I am trying to loop through a file which contains few names and search the same with two patterns in another file and echo some statements.
Like I have two files :
1.Installers.txt
2.Progress.txt
Installers.txt
abc.jar
def.jar
tef.jar
....
....
Progress.txt
abc.jar deployment started
abc.jar deployed successfully
def.jar deployment started
So my requirement is to read the Installers.txt file one line at a time and search for the 2 patterns "abc.jar deployment started" and "abc.jar deployed successfully" and report successful or else if both patterns are yet to be found to show as still in progress.
I have tried writing below but its failing at many things while doing pattern and the logic also does not look good. can someone help here.
for /F "usebackq delims=" %%a in ("Installer.txt") do (
set /A i+=1
call echo installing %%i%% : %%a
:NOTVALID
findstr /I "%%k\ in\ progress" %1%\progress.txt
If errorlevel 1 (
echo "installation still in progress.."
PING 127.0.0.1 -n 1 >NUL 2>&1 || PING ::1 -n 1 >NUL 2>&1
goto NOTVALID
) else (
set /A i+=1
echo "installation completed.."
call set array[%%i%%]=%%a
call set n=%%i%%
)
Try the below code which suite your requirement :
cls
#echo off
for /f %%g in (Installers.txt) do type Progress.txt|findstr "%%g" || echo %%g is Yet to start , still in progress
Above code will read a single line from installer and then search for that string in file Progress.txt and then print the output if it is found or not.

What is wrong with goto command in for loop?

I have a list of computers that I want to make some things according to tcp connection status.
I'm trying to check tcp connection and if errorlog is "1" so write line to log and skip to next computer.
The problem is that when a computer has no tcp connection the goto skip_action command takes the script to the end and exit and the other computers in the list left unprocessed.
I have also tried to use goto :eof and it terminates the script unexpected.
ipst.txt file:
1 10.1.1.10
3 10.1.3.10
8 10.1.3.10
This is the batch file code:
#echo off
setlocal enabledelayedexpansion
set computerslist=ipst.txt
for /f "usebackq tokens=1,2" %%A in ("%Computerslist%") do (
cls
set Station_Num=%%A
set Comp_IP=%%B
ping !Comp_IP! -n 1 | findstr "TTL"
if !errorlevel!==1 (
echo Station !Station_Num! .... !Comp_IP! ..................... No Communication.>>%log%
goto skip_action
)
echo Getting Administrator Credentials:
net use \\!Comp_IP! /USER:WORKGROUP\****** ******
echo.
xcopy file.txt \\!Comp_IP!\c\temp\
echo Disconneting Session From Remote Computer :
net use \\!Comp_IP! /DELETE /YES
:skip_action
echo end of working on !Station_Num!
)
echo end of script
The problem here is that GOTO cancels the for loop.
But you can simply enclose your action in an ELSE block
for /f "usebackq tokens=1,2" %%A in ("%Computerslist%") do (
cls
set Station_Num=%%A
set Comp_IP=%%B
ping !Comp_IP! -n 1 | findstr "TTL"
if !errorlevel!==1 (
echo Station !Station_Num! .... !Comp_IP! ..................... No Communication.>>%log%
) Else (
echo Getting Administrator Credentials:
net use \\!Comp_IP! /USER:WORKGROUP\****** ******
echo.
xcopy file.txt \\!Comp_IP!\c\temp\
echo Disconneting Session From Remote Computer :
net use \\!Comp_IP! /DELETE /YES
)
echo end of working on !Station_Num!
)
General form of if - else statement
If condition (
Statements
) else (
Statements to be executed if condition is not met
)
Make your call from the loop
You can have a function ping .. and parse variable references to it .. the preceding code could also be rendered as %%a and %%b being the first and second argument respectively -- in your function call ...
Call :pingcomputers %%a %%b
This way you avoid set altogether
:pingcomputers
Rem Pinging computer %~1
Ping %~2 ¦ find "reply"
If errorlevel 1 goto failed
(Actions to be performed if ping wa successful)
Assuming that your script has a label failed and actions to.be performed if error level is not 0 ..
Not much of a script but hope it helps ...

Resources