What is wrong with goto command in for loop? - batch-file

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 ...

Related

Power Management Batch File to shutdown pc when another pc shuts down/hibernates/looses connectivity

this is my first post here so please excuse me for getting anything wrong.
I have a few computers that run Octane renderer. One is the "Master" and the others are "Slaves". When the Master is unreachable the Slaves can't render so I'd like to save money and the environment by having a small batch script for when this happens.
My thinking to a solution was to have a batch script on the Slaves to ping the Master every 5 mins to check there is a connection. When the ping fails it tries again 3 times and if it fails every time the Slave shuts down.
I've got this script from another post here that I did minor edits to : Batch File to reboot pc on network connectivity loss but it doesn't work for what I need. When I run it with the ping ip set to the Master's ip it says my connection is active. When attempting to ping the Master in a command prompt I get "destination host unreachable". Any help would be greatly appreciated!
set ping_ip=1.1.1.1
set failure_count=0
set timeout_secs=300
set connection_error_count=0
set max_connection_error_count=3
:start
:: calling the ping function
call :connection_test
:: Processing the network "up" state
if "%network_state%"=="up" (
echo INFO: You have an active connection.
set connection_error_count=0
) else (
set /a connection_error_count+=1
)
:: Processing the network "down" state
if "%network_state%"=="down" (
if %connection_error_count% geq %max_connection_error_count% (
echo ERROR: You do not have an active connection.
goto poweroff
) else (
echo INFO: FAILURE: That failed [%connection_error_count%] times, NOT good. lets try again...
goto start
)
)
timeout /t %timeout_secs%
goto start
:: connection_test function
goto skip_connection_test
:connection_test
:: Getting the successful ping count
echo INFO: Checking connection, please hang tight for a second...
for /f "tokens=5 delims==, " %%p in ('ping -n 4 %ping_ip% ^| findstr /i "Received"') do set ping_count=%%p
:: Check the ping_count against the failure_count
if "%ping_count%" leq "%failure_count%" (
set network_state=down
) else (
set network_state=up
)
goto :eof
:skip_connection_test
:: Power off
:poweroff
echo INFO: Shutdown PC in 60 seconds. Press any key to abort.
shutdown -s -t 60 -f
pause > nul
shutdown -a
goto end
:end ```
Your code is quite large for something so simple. First, the address you set on ipv4 is not the correct address!
You can access my repository to read how to acquire your IPv4 code here.
After obtain your IPv4 address, add to your code:
ping %ipv4% -n 9 | findstr /i "unreach">filex.txt
set /p stop=<filex.txt
if "%stop%" neq "" (
:: put here your shutdown preferences.
)
If you want something like what you are searching for:
#echo off
:verif
set points=
echo INFO: Checking connection, please hang tight for a second...
ping %ipv4% -n 3 | findstr /i "unreach">filex.txt
set /p stop=<filex.txt
if "%stop%" neq "" set /a points=%points%+1
del /q /f filex.txt
ping %ipv4% -n 3 | findstr /i "unreach">filed.txt
set /p stopd=<filed.txt
if "%stopd%" neq "" set /a points=%points%+1
:: Add points as you want.
if "%points%" geq "2" (
set shutdown=y
)
if "%shutdown%" equ "y" (
echo ERROR: You do not have an active connection.
shutdown -s -t 60 -f
echo INFO: Shutdown PC in 60 seconds. Press any key to abort.
pause>nul
shutdown -a
goto verif
)
echo INFO: You have an active connection.
goto verif
Hope this helps,
K.

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();
}

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.

'for' loop variable not releasing on loop iterations

Been wrecking my brain all night trying to figure out why this isn't working, but one of my variables isn't releasing on the next iteration of my loop and I can't figure out why... The first pass of the loop seems to work fine, but the next iteration, the first variable gets locked and the script connects to the system that's already been configured.
I've been staring at this for a while now and no matter how I approach it, it still behaves badly. :/ The purpose is to read a text-string of a given file, and use it to modify (via Find and Replace (fnr.exe)) another file with several instances of the required data. I didn't have alot of luck with 'findstr' replacing so many instances of the text required so I went with a tool I've used before that seemed to work really well in it's previous scripting application...
Truth be told, I find myself stumbling with even the most basic code a lot of times, so any kind soul willing to impart some wisdom/assistance would be greatly appreciated!
Thanks in advance...
#ECHO ON
setlocal enabledelayedexpansion
> "%~dp0report.log" ECHO Batch Script executed on %DATE% at %TIME%
rem read computer list line by line and do
FOR /F %%A in (%~dp0workstations.txt) do (
SET lwn=
SET WKSTN=%%A
rem connect to workstation and read lwn.txt file
pushd "\\%WKSTN%\c$\"
IF ERRORLEVEL 0 (
FOR /F %%I in (\\%wkstn%\c$\support\lwn.txt) DO (
SET LWN=%%I
%~dp0fnr.exe --cl --dir "\\%WKSTN%\c$\support\folder\config" --fileMask "file.xml" --find "21XXXX" --replace "%%I"
IF ERRORLEVEL 0 ECHO Station %LWN%,Workstation %WKSTN%,Completed Successfully >> %~dp0report.log
IF ERRORLEVEL 1 ECHO Station %LWN%,Workstation %WKSTN%, A READ/WRITE ERROR OCCURRED >> %~dp0report.log
echo logwrite error 1 complete
popd
)
)
IF ERRORLEVEL 1 (
ECHO ,,SYSTEM IS OFFLINE >> %~dp0report.log
)
popd
set wkstn=
set lwn=
echo pop d complete
)
msg %username% Script run complete...
eof
The ! notation must be used on all variables that are changed inside the loop.
C:>type looptest.bat
#ECHO OFF
setlocal enabledelayedexpansion
rem read computer list line by line and do
FOR /F %%A in (%~dp0workstations.txt) do (
SET WKSTN=%%A
ECHO WKSTN is set to %WKSTN%
ECHO WKSTN is set to !WKSTN!
pushd "\\!WKSTN!\c$\"
ECHO After PUSHD, ERRORLEVEL is set to %ERRORLEVEL%
ECHO After PUSHD, ERRORLEVEL is set to !ERRORLEVEL!
IF !ERRORLEVEL! NEQ 0 (
ECHO ,,SYSTEM IS OFFLINE
) ELSE (
ECHO Host !WKSTN! is available
)
popd
)
EXIT /B 0
The workstations.txt file contained the following. (I should not give out actual host names.)
LIVEHOST1
DEADHOST1
LIVEHOST2
The output is...
C:>call looptest.bat
WKSTN is set to
WKSTN is set to LIVEHOST1
After PUSHD, ERRORLEVEL is set to 0
After PUSHD, ERRORLEVEL is set to 0
Host LIVEHOST1 is available
WKSTN is set to
WKSTN is set to DEADHOST1
The network path was not found.
After PUSHD, ERRORLEVEL is set to 0
After PUSHD, ERRORLEVEL is set to 1
,,SYSTEM IS OFFLINE
WKSTN is set to
WKSTN is set to LIVEHOST2
After PUSHD, ERRORLEVEL is set to 0
After PUSHD, ERRORLEVEL is set to 0
Host LIVEHOST2 is available
Although your code have several issues, the main one is the use of % instead of ! when you access the value of variables modified inside a for loop (although you already have the "enabledelayedexpansion" part in setlocal command). However, I noted that you sometimes use the FOR replaceable parameter (like in --replace "%%I") and sometimes you use the variable with the same value (%LWN%), so a simpler solution in your case would be to replace every %VAR% with its corresponding %%A for parameter.
I inserted this modification in your code besides a couple small changes that make the code simpler and clearer.
#ECHO ON
setlocal
> "%~dp0report.log" ECHO Batch Script executed on %DATE% at %TIME%
rem Read computer list line by line and do
FOR /F %%A in (%~dp0workstations.txt) do (
rem Connect to workstation and read lwn.txt file
pushd "\\%%A\c$\"
IF NOT ERRORLEVEL 1 (
FOR /F "usebackq" %%I in ("\\%%A\c$\support\lwn.txt") DO (
%~dp0fnr.exe --cl --dir "\\%%A\c$\support\folder\config" --fileMask "file.xml" --find "21XXXX" --replace "%%I"
IF NOT ERRORLEVEL 1 (
ECHO Station %%I,Workstation %%A,Completed Successfully >> %~dp0report.log
) ELSE (
ECHO Station %%I,Workstation %%A, A READ/WRITE ERROR OCCURRED >> %~dp0report.log
echo logwrite error 1 complete
)
)
) ELSE (
ECHO ,,SYSTEM IS OFFLINE >> %~dp0report.log
)
popd
echo pop d complete
)
msg %username% Script run complete...

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

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

Resources