Batch file to ping and display different output - windows

I'm trying to create a batch file to ping a few devices to output a .txt that shows the results.
ping -n 1 router | find "TTL" > nul
IF errorlevel 1 (
echo "Cannot ping" > DIRECTORY
)
ELSE (
echo "Ping success" > DIRECTORY
)
Currently I can only show whether it succeeds or fails. However I'm thinking if there is a way to differentiate between how it fails e.g. request time out VS host unreachable.
Does anyone know how I can tweak it?
EDIT:
#echo off
for /f "delims=" %%i in ('ping -n 2 router ^| findstr "Reply timed Hardware"') do set "res=%%~i"
if not "%res:timed=%" == "%res%" echo "Time out" > C:\Users\eddie\Desktop\results\timeout.txt
if not "%res:unreachable=unreachable%" == "%res%" echo "Destination host is unreachable" > C:\Users\eddie\Desktop\results\unreach.txt
if not "%res:Reply=%" == "%res%" echo "successful ping" > C:\Users\eddie\Desktop\results\success.txt
pause

Here is an untested example, I cannot test this now because I am not able to setup any routing that will create various results such as Destination host unreachable which comes from the router:
#echo off
set "host=router"
for /f "delims=" %%i in ('ping -n 2 %host% ^| findstr "TTL timed request unreachable"') do set "res=%%~i"
if not "%res:timed=%" == "%res%" (echo Time out)>"%userprofile%\Desktop\timeout.txt"
if not "%res:request=%" == "%res%" (echo Unknown Host)>"%userprofile%\Desktop\unknownhost.txt"
if not "%res:unreachable=unreachable%" == "%res%" (echo Destination host is unreachable)>"%userprofile%\Desktop\unreach.txt"
if not "%res:TTL=%" == "%res%" (echo Successful ping)>"%userprofile%\Desktop\success.txt"
The concept is simply, the findstr will capture only results from any of Reply or timed or hardware. We then just test if the string contains a substring and echo accordingly.
The second option in the list to capture unreachable has the & goto :EOF option simply because it will contain either just destination host unreachable or Reply from ... : Destination host unreachable like the below screenshot. We do not want to create both messages for Unreachable and Reply (which comes from the Router).

Related

In BAT file script, add new line in FILE if FILE doesn't contain that line

I want to add one line in hosts file:
127.0.0.1 new-host
if it doesn't contain this line.
In windows use bat scripting.
Example 1
before script:
127.0.0.1 db
127.0.0.1 host
after script:
127.0.0.1 db
127.0.0.1 host
127.0.0.1 new-host
Example 2
before script:
127.0.0.1 db
127.0.0.1 host
127.0.0.1 new-host
after script:
127.0.0.1 db
127.0.0.1 host
127.0.0.1 new-host
My code:
for /f "delims=" %%i in ('findstr /c:"new-host" "c:\Windows\System32\Drivers\etc\hosts"') do set actualLineHost=%%i
echo %actualLineHost%
if "%actualLineHost:"=.%"==".." (
echo empty
goto empty
) else (
echo not empty
goto notempty
)
findstr /c:"new-host" "c:\Windows\System32\Drivers\etc\hosts" works fine in command line returns nothing, but when I run a script a have "not empty" when file doesn't contain line.
Try this code :
#echo off
findstr /m "new-host" C:\Windows\System32\drivers\etc\hosts
if %errorlevel%==0 (
echo Found!
) else (
echo No matches found
echo 127.0.0.1 new-host >> C:\Windows\System32\drivers\etc\hosts
)
pause
This will launch findstr cmd to search one (or more ) define string in a file, after this, we check if command return error or not, is there is no error, we made an echo to write the line in the file ( >> is for going new line )
Solution without using errorlevel
for /f "delims=" %%i in ('findstr /c:"new-host" "c:\Windows\System32\Drivers\etc\hosts"') do goto hostContains
echo 127.0.0.1 new-host >> c:\Windows\System32\Drivers\etc\hosts
echo "Not found"
goto exit
:hostContains
echo "Found"
:exit

Variable not emptied in batch script after set to empty

I'm trying to make a batch script which is supposed to ping a site, log the results, and start a program if the results were negative. This is a modification of original script (not mine), which can be found here. Values of domain, IP, and program variables are for illustrative purposes.
#echo off
cls
set domain=testsite.com
set IP=133.78.17.101
set program=c:\windows\notepad.exe
set output=c:\log.txt
set result=1
:Start
IF [%result%]==[] (
>>%output% echo -----------
start %program%
)
ECHO Pinging %domain%...
FOR /F "delims=" %%G in ('ping -n 1 %domain% ^| find "Reply"') DO SET result=%%G
IF NOT [%result%]==[] (
goto Success
) ELSE (
goto TryAgain
)
:TryAgain
ECHO %domain% unreachable. Trying again...
FOR /F "delims=" %%G in ('ping -n 1 %domain% ^| find "Reply"') DO SET result=%%G
IF NOT [%result%]==[] (
goto Success2
) ELSE (
goto TryIp
)
:TryIp
ECHO %domain% unreachable. Pinging %ip%...
FOR /F "delims=" %%G in ('ping -n 1 %IP% ^| find "Reply"') DO SET result=%%G
IF NOT [%result%]==[] (
goto SuccessDNS
) ELSE (
goto TestInternet
)
:TestInternet
ECHO %ip% unreachable. Testing internet connection.
FOR /F "delims=" %%G in ('ping -n 1 www.google.com ^| find "Reply"') DO SET result=%%G
IF NOT [%result%]==[] (
goto Success3
) ELSE (
goto NetDown
)
:Success
>>%output% ECHO Connected
>>%output% echo %date% %time% %result%
ping -n 3 127.0.0.1 > nul
goto Start
:Success2
>>%output% ECHO Connected with packet loss.
>>%output% echo %date% %time% %result%
set result=
ping -n 3 127.0.0.1 > nul
goto Start
:Success3
>>%output% ECHO Domain %domain% not reachable. Connected via IP.
>>%output% echo %date% %time% %result%
set result=
ping -n 3 127.0.0.1 > nul
goto Start
:SuccessDNS
>>%output% ECHO DNS problem.
>>%output% echo %date% %time% %result%
set result=
ping -n 3 127.0.0.1 > nul
goto Start
:NetDown
>>%output% ECHO No internet connection.
>>%output% echo %date% %time% %result%
set result=
ping -n 3 127.0.0.1 >nul
goto Start
What I'm trying to achieve is this - if anything other than a perfect reply to a ping request is received, the script should start a program. To secure that this happens only then, I've been clearing the result variable every time, other than on an expected ping response.
Echoing the value of result keeps returning 1, even after I've emptied it.
in your line
FOR /F "delims=" %%G in ('ping -4 -n 1 %domain% ^| find "Reply"') DO SET result=%%G
%%G is either not defined (when the word Reply doesn't occur), which doesn't touch your Result variable at all,
or a line like Reply from x.x.x.x : Bytes=32 Time<1ms TTL=128, which definitively isn't empty.
According to the rest of your code, you probably meant ... DO SET "result=" to unset the variable.
Note: searching for "Reply" is
a) language dependent ("Antwort" on German Windows) and
b) not reliable (think of Reply from localhost: destination address unreachable).
Better search for TTL= (even works without a for loop):
ping -n 1 %IP% | find "TTL=" >nul && set "reply=true" || set "reply=false"
echo %reply%
Just an addendum to Stephan's post.
In addition to reasons posted in Stephan's post, the code was not working as I had originally planned it to, because the comparisons were failing as well. If there was a successful ping, the result variable was being set to a string consisting of multiple words, which was breaking the comparison. To avoid this, I had to change every instance of
IF [%result%]==[]
to
IF ["%result%"]==[""]
Thomas Weller's (now deleted) comment was also on the right track - I did need to empty the result variable in :Start:
:Start
IF ["%result%"]==[""] (
>>%output% echo -----------
start %program%
)
SET result=
ECHO Pinging %domain%...
This emptying was needed to annul any previous successes and the original set result=1 (in case of consistent failures).

Windows batch script to see if a sequence of server/ports is open?

I can run a single command to see if a port is open:
portqry -n servername -e 80
I want to run this against a list of servers:
DEV1 80
DEV2 80
DEV3 80
TEST1 80
TEST2 80
PROD 80
I want to test them all using a single Windows batch script and see which portsare open and which ones are closed. (And I don't want it to fall over on the first closed port).
My question is: Is there a Windows batch script to see if a sequence of server/ports is open?
Additional: I'm aware there are other questions asking how to check if a port is open. None of them are about scripting it for a sequence of ports in a reliable way.
Here you go. Pay it forward. :) To answer your question directly, just use a for loop to loop through your servers and perform a portqry on each. Edit: That PowerShell snippet you found is useful for getting rid of the PortQry dependency.
#echo off
setlocal
set "servers=dev1 dev2 dev3 test1 test2 test2:8080 prod prod:443"
for %%I in (%servers%) do (
for /f "tokens=1,2 delims=:" %%a in ("%%I") do (
set "port=%%~b"
if not defined port set "port=80"
setlocal enabledelayedexpansion
call :handshake "%%~a" "!port!" && (
echo %%a port !port!: OK
) || (
echo %%a port !port!: Error
)
endlocal
)
)
goto :EOF
:handshake <server> <port>
powershell "$t=new-object Net.Sockets.TcpClient;$c=$t.BeginConnect('%~1',%~2,{},{});if($c.AsyncWaitHandle.WaitOne(1000)){$t.EndConnect($c);exit 0};exit 1"
exit /b %ERRORLEVEL%
Here's the original solution using PortQry 2.0:
#echo off
setlocal
set "servers=dev1 dev2 dev3 test1 test2 test2:8080 prod prod:443"
for %%I in (%servers%) do (
for /f "tokens=1,2 delims=:" %%a in ("%%I") do (
set "port=%%~b"
if not defined port set "port=80"
setlocal enabledelayedexpansion
portqry -n "%%~a" -e "!port!" >NUL 2>NUL && (
echo %%a port !port!: OK
) || (
echo %%a port !port!: Error
)
endlocal
)
)
If all you are testing are web services, it might make more sense to go about this in a different way. You can use the Microsoft.XMLHTTP COM object to get rid of that portqry dependency; and the responses acquired thusly will be more relevant to HTTP services. (For example, if you've got a VNC server running on port 8080 where you expect a web service to be listening instead, portqry would probably return success when you'd need it to return fail.)
Anyway, save this as a .bat script and salt to taste.
#if (#CodeSection == #Batch) #then
#echo off
setlocal
set "servers=dev1 dev2 dev3 test1 test2 test2:8080 prod prod:443"
for %%I in (%servers%) do (
for /f "tokens=1,2 delims=:" %%a in ("%%I") do (
set "port=%%~b"
if not defined port set "port=80"
setlocal enabledelayedexpansion
cscript /nologo /e:JScript "%~f0" "%%~a" "!port!" && (
echo %%a port !port!: OK
) || (
echo %%a port !port!: Error
)
endlocal
)
)
goto :EOF
#end // end batch / begin JScript chimera
var server = WSH.Arguments(0),
port = WSH.Arguments(1),
protocol = port == 443 ? 'https' : 'http',
URL = protocol + '://' + server + ':' + port + '/',
XHR = WSH.CreateObject('Microsoft.XMLHTTP');
XHR.open('GET', URL);
XHR.setRequestHeader('User-Agent','XMLHTTP/1.0');
XHR.send('');
while (XHR.readyState != 4) WSH.Sleep(25);
WSH.Quit(XHR.status - 200);
This is what I ended up replacing the VBScript above with - a file called porttest.ps1 which is run with powershell -f porttest.ps1
param(
[string] $remoteHost = "arbitrary-remote-hostname",
[int] $port = 23
)
# Open the socket, and connect to the computer on the specified port
write-host "Connecting to $remoteHost on port $port"
$tcpobject = new-Object system.Net.Sockets.TcpClient
$connect = $tcpobject.BeginConnect($remoteHost,$port,$null,$null)
#Configure a timeout before quitting - time in milliseconds
$wait = $connect.AsyncWaitHandle.WaitOne(1000,$false)
If (-Not $Wait) {
'Timeout'
exit 1
} Else {
$error.clear()
$tcpobject.EndConnect($connect) | out-Null
If ($Error[0]) {
Write-warning ("{0}" -f $error[0].Exception.Message)
exit 1
} Else {
'Port open!'
exit 0
}
}
Unlike the above this does not require powershell at all and should work with all versions of windows provided the telnet client has been installed (dism /online /Enable-Feature /FeatureName:TelnetClient)
If someone can work out how to stop the telnet command outputting anything please add a comment, because if I add a redirect it refuses to run. I believe telnet requires a stdout and cannot be redirected.
For this to work just change the two 127.0.0.1 IP addresses to the host you are wanting to scan.
break>Results.txt & (for /l %a in (1,1,49152) do #taskkill /im telnet.exe /f >NUL 2>&1 & #start /b telnet.exe 127.0.0.1 %a & for /f %i in ('netstat -n ^| findstr /r /c:"TCP[ ][ ]*127.0.0.1:%a[ ][ ]*.*ESTABLISHED" ^| findstr /n ".*" ^| findstr "^1:"') do #echo "TCP Port Open: %a" >> Results.txt) & taskkill /im telnet.exe /f >NUL 2>&1
Once it has finished, to get the results you can type
type Results.txt

Add "if arguement" against a Pipe for a variable

I'm new at writing code and batch files. I'm trying to automate a user setup by allowing the user to issue the following batch file:
Command Executed = "BVT_AudioDecode_Setup.bat V:\WP\BVT\Audio\Decode 10.42.233.237"
#echo off
::Conditions leading to errors if the batch script is not executed correctly
if "%1"=="" and "%2"=="" goto error1
if "%1"=="" goto error2
if "%2"=="" goto error3
::Allows user to set the "Source Path" to copy the testcase files from
set source=%1
::Allows user to set the "Destination Path" to copy the testcase files from
set IP_Address=%2
::Tells the user what the "Source" and "Destination" Paths are
echo Source Path = %1
echo Destination Path = %2
echo.
powershell.exe -File "bat_script.ps1" %1 %2 -NoProfile -NoExit
goto end
:error1
echo.
echo Error Syntax: BVT_AudioDecode_Setup.bat "Source_Path\AudioDecode_Testcase_Folder" "Device IP Address"
echo.
echo For example: BVT_AudioDecode_Setup.bat V:\WP\BVT\Audio\Decode 10.42.233.237
echo -or-
echo BVT_AudioDecode_Setup.bat C:\WP\BVT\Audio\Decode 10.42.233.237
echo.
echo.
goto end
:error2
echo.
echo Error Syntax: BVT_AudioDecode_Setup.bat "Source_Path\AudioDecode_Testcase_Folder" "Device IP Address"
echo.
echo For example: BVT_AudioDecode_Setup.bat V:\WP\BVT\Audio\Decode 10.42.233.237
echo -or-
echo BVT_AudioDecode_Setup.bat C:\WP\BVT\Audio\Decode 10.42.233.237
echo.
echo.
goto end
:error3
echo.
echo Error Syntax: BVT_AudioDecode_Setup.bat "Source_Path\AudioDecode_Testcase_Folder" "Device IP Address"
echo.
echo For example: BVT_AudioDecode_Setup.bat V:\WP\BVT\Audio\Decode 10.42.233.237
echo -or-
echo BVT_AudioDecode_Setup.bat C:\WP\BVT\Audio\Decode 10.42.233.237
echo.
echo.
goto end
:end
This was tested and it works.
Now I am trying to add/test a simple block of code, but I cannot find the correct syntax. Yes, I have been googling for the last 3 hours. Here is what I am trying to do:
Command Executed = "Random.bat C:\Users"
Command Executed = "Random.bat C:\InvalidDirectory"
::Conditions leading to errors if the batch script is not executed correctly
#ECHO OFF
SET "mypath=%1"
ECHO %mypath%
cd %mypath% | find "%invalidpath%"
Echo %invalidpath%
If "%invalidpath%=The system cannot find the path specified." (
goto error1)
else (
goto BeginTest)
::Begins the testcase
:BeginTest
::Do some stuff
goto end
:error1
echo Error: Invalid Path
goto end
:end
If anyone could point me in the right direction it would be much appreciated...
You can use the IF EXIST statement to check for the presence of a directory. For example, to test for C:\WIN and then change to C:\WIN if it exists :
C:
IF NOT EXIST "C:\WIN\." GOTO NOWINDIR
CD \WIN
:NOWINDIR
because the "not-found-answer" from "cd xxxx" will vary with the language of your windows-installation you should prefer a language-independent solution.
Use %errrorlevel% for that.
cd c:\existingpath\ will return an errorlevel of "0"
cd c:\notexistingpath\ will return "1"
so a good solution would be:
SET "mypath=%1"
ECHO %mypath%
cd %mypath%
If %errorlevel%=0 goto BeginTest else goto error1
...
It worked, thanks. Here is what I have in case anyone else runs into this problem:
::Conditions leading to errors if the batch script is not executed correctly
#ECHO OFF
SET "source=%1"
ECHO %source%
IF NOT EXIST "%source%" goto error1
ECHO Directory Exists
cd %source%
goto end
:error1
echo Error: Invalid Path
goto end
:end
Now I need an if condition for a true IP Address
::Conditions leading to errors if the batch script is not executed correctly
#ECHO OFF
SET "IP_Address=%1"
ECHO %IP_Address%
::Checks if the IP Address is valid
IF NOT EXIST "%IP_Address%" goto error2
ECHO Directory Exists
goto end
:error1
echo.
echo Error: Invalid Path
echo %source%
goto end
:error2
echo.
echo Error: Invalid IP Address
echo %IP_Address%
goto end
:end
It automatically checks to see if the IP Address is a path. I could add a "\\" in front of the "IF NOT EXIST "\\%IP_Address%" goto error2", but the issue with this is that the computer will not be able to connect to the device unless it uses either telnet, or "Open-Device" command through powershell. It can however ping that IP Address.
Is there is a way to setup to read a successful ping vs unsuccessful ping??
same solution with %errorlevel%
ping -n 1 -w 100 %ip-address%
if %errorlevel%=0 then goto doesexist else goto cannotreach
...
All commands will return an errorlevel. Normally Zero, if all was ok, and a non-zero- value for errors.
It's still not working correctly with the IP address listing, but I am closer with your help. Here is what I have when I execute the bat with a valid IP Address to ping:
::Conditions leading to errors if the batch script is not executed correctly
#ECHO OFF
SET IP_Address=%1
ECHO %IP_Address%
::Checks if the IP Address is valid
ping -n 1 -w 1000 %IP_Address%
if not "%errorlevel%=0" goto error2
goto end
:error2
echo.
echo Error: Invalid IP Address
echo %IP_Address%
goto end
:end
Upon execution this is what I am seeing in cmd:
c:\>Random.bat 192.168.1.46
192.168.1.46
Pinging 192.168.1.46 with 32 bytes of data:
Reply from 192.168.1.46: bytes=32 time=1ms TTL=128
Ping statistics for 192.168.1.46:
Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 1ms, Maximum = 1ms, Average = 1ms
goto was unexpected at this time.
Once this is solved, I would also like to know a way to hide the output:
Pinging 192.168.1.46 with 32 bytes of data:
Reply from 192.168.1.46: bytes=32 time=1ms TTL=128
Ping statistics for 192.168.1.46:
Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 1ms, Maximum = 1ms, Average = 1ms
to hide the output use >nul
ping -n 1 -w 1000 %IP_Address% 1>nul 2>nul
1>nul will send the "normal" output to nirvana
2>nul will send the errormessages to nirvana
So if you use " 1>nul" (or just " >nul") you will have the errormessage on the screen, but not the "reply", "statistics" and that kind of stuff.
I don't understand the "unexpected goto" just now - I will have a look on that tomorrow.
Ah I finally found it after looking up usage for errorlevel
::Conditions leading to errors if the batch script is not executed correctly
#ECHO OFF
SET IP_Address=%1
ECHO %IP_Address%
::Checks if the IP Address is valid
ping -n 1 -w 100 %IP_Address% 1>nul
if "%errorlevel%"=="1" goto error2
:error2
echo.
echo Error: Invalid IP Address
echo %IP_Address%
goto end
:end
Thanks for the help everyone.

run a batch file for every alive machine in a /24 network

The script in its current form
#echo on
setlocal EnableDelayedExpansion
set /p ipAddress="enter ip address: "
rem right now the loop is set to (1,1,50) for the sake of testing
for /l %%i in (1,1,50) do (
ping -n 1 %ipAddress%.%%i | find "TTL" > nul
if !errorlevel! == 0 (
deploy_mir.bat %ipAddress%.%%i
)
)
endlocal
and then the result of running it on a known to be online host (10.167.194.22) is
C:\DOCUME~1\socuser2\MIR>test.bat
C:\DOCUME~1\socuser2\MIR>setlocal EnableDelayedExpansion
C:\DOCUME~1\socuser2\MIR>set /p ipAddress="enter ip address: "
enter ip address: 10.167.194
C:\DOCUME~1\socuser2\MIR>for /L %i in (22 1 50) do (
ping -n 1 10.167.194.%i | find "TTL" 1>nul
if !errorlevel! == 0 (deploy_mir.bat 10.167.194.%i )
)
C:\DOCUME~1\socuser2\MIR>(
ping -n 1 10.167.194.22 | find "TTL" 1>nul
if !errorlevel! == 0 (deploy_mir.bat 10.167.194.22 )
)
"Mir Agent deployment to: 10.167.194.22"
Now that last line there means that !errorlevel! == 0 (ie, "TTL" was indeed found)
so up to this point it looks like the script is working. However on the next loop, 10.167.194.23 (alive) got skipped as well as .30 and .46 . I decided to add
echo %errorlevel%
at the end of the loop to see whats going on here. Apparently, after every ping %errorlevel% was 0 so clearly
ping -n %ipAddress%.%%i | find "TTL" >nul
is where my issue is. According to this statement, "TTL" is being found after every ping, which is false, between 10.167.194.22-.50 only 3 machines are alive.
by the way, when i do
!errorlevel! == 0
what does that mean?
Everything below this line is as of 4/26/12
So my new script looks like this
#echo on
set /p ipAddress="enter ip address: "
set i=
for /l %%i in (1,1,255) do (
ping -n 1 %ipAddress%.%%i> test.txt
find "TTL" test.txt
if %errorlevel% == 0 (
deploy_this.bat %ipaddress%.%%i
)
i first tried the script without the if errorlevel check,
and it worked fine. It started pinging the ip address that i provided and proceeded to .2 .3 .4 .5 and so on.
once i added this however...
if %errorlevel% == 0 (
deploy_this.bat %ipaddress%.%%i
)
this is what happens
C:\DOCUME~1\socuser2\MIR>test.bat
C:\DOCUME~1\socuser2\MIR>set /p ipAddress="enter ip address: "
enter ip address: 10.167.201
C:\DOCUME~1\socuser2\MIR>set i=
C:\DOCUME~1\socuser2\MIR>
and the script just stops dead. any ideas?
There are a few issues :
A batch file will never return unless you use the call statement
You are missing a parenthesis
Inside a FOR loop, you must enabledelayedexpansion and use !ERRROLEVEL!
I suggest you look at this code, it has a few improvements :
It use setlocal to keep its variable to itself
It does not produce a temp file
Can take the ip address from the command line or prompt for it
It is indented
It is less verbose in its output
Here it is :
#echo off
setlocal EnableDelayedExpansion
set ipAddress=%1
if "%ipAddress%"=="" SET /P ipAddress="enter ip address: "
for /l %%i in (1,1,2) do (
rem Remove the > nul at the end if you want to
rem see the ping results in the output
ping -n 1 %ipAddress%.%%i | find "TTL" > nul
if !ERRORLEVEL! == 0 (
call deploy_this.bat %ipAddress%.%%i
)
)
endlocal
Perhaps I would rewrite your loop like this:
FOR /L %%i IN (1,1,50) DO (
ping -n 1 %ipAddress%.%%i | find "TTL" >NUL && (
CALL deploy_mir.bat %ipAddress%.%%i
)
)
Language-independent ping reply analysis would be like below:
ping -n 1 %ipAddress%.%%i
if errorlevel 1 goto :dead

Resources