I know breaking out of a nested loop is fairly easy, however, I'm not sure how to do it when I'm working with multiple lists of servers. Here's the scenario:
Goal: Search for sessions on a server matching a specific user ID, and also kill any disconnected sessions found
Problem: I have multiple lists of farms. I want to cycle through the lists until I find the users session, and then stop when that list is finished (not stop when the session is cleared, they may have multiple sessions in the farm).
Farmlist1.txt
farmlist2.txt
farmlist3.txt
If the session is found in farmlist2.txt, I want to FINISH searching in that list, but don't continue to farmlist3.txt.
Here's what I have so far, and it works like a charm. (Optimizations welcomed)
@echo off
echoCitrix Session Reset
echo.
echo This will look for a specific userID AND kill disconnected sessions on all servers!
set /p userid=User ID of the user:
for %%a in (q:\scripts\1common\citrixlists\*.txt) do (
for /f "tokens=*" %%l in (%%a) do (
ping %%l -n 1 | find /i "TTL=" > nul
if errorlevel 1 (
echo server %%l down or out of Load
) else (
echo Looking for %username% and killing disconnected sessions on %%l
for /f "tokens=3" %%b in ('qwinsta *tcp /server:%%l ^| find /i "%userid%"') do echo %%b | rwinsta %%b /server:%%l && echo SESSION FOR %userid% KILLED ON %%l
for /f "tokens=2" %%i IN ('qwinsta /server:%%l ^| find /i "disc"') DO (
if %%i gtr 0 (
rwinsta %%i /server:%%l && echo Disconnected sessions terminated
)
)
)
)
)
I do not exactly understand what you are trying to accomplish, but I do understand how to break out of nested for
loops (or any other nested parenthesised blocks of code). So let me elaborate on that.
Breaking a single for
loop is simple: put goto :STOP
into the loop and the label :STOP
in the line following the loop structure. The example below breaks the loop depending on its loop counter value:
@echo off
for /L %%I in (0,1,5) do (
if %%I GTR 3 (
echo Break!
goto :STOP
)
echo %%I
)
:STOP
Although the loop is specified to count up to 5
, the output is:
0
1
2
3
Break!
Note that the loop actually completes the counting internally, but no more commands are executed. You can easily reproduce that when you increase the end value 5
to a huge number like 1000000
.
But now let us concentrate on nested loops (two in each example):
The following code snippet breaks both loops upon a certain condition is met:
@echo off
for %%J in (Aa Bb Cc) do (
for /L %%I in (0,1,5) do (
if "%%~J"=="Bb" if %%I GTR 3 (
echo Break!
goto :STOP
)
echo %%J-%%I
)
)
:STOP
The output is:
Aa-0
Aa-1
Aa-2
Aa-3
Aa-4
Aa-5
Bb-0
Bb-1
Bb-2
Bb-3
Break!
As you can see, execution of the loop construct is interrupted immediately at a certain point.
The batch file here breaks the outer loop when the a certain condition in the inner loop is met. The result of the check is transferred to the outer loop using a variable FLAG
:
@echo off
set "FLAG="
for %%J in (Aa Bb Cc) do (
for /L %%I in (0,1,5) do (
if "%%~J"=="Bb" if %%I GTR 3 (
echo Break!
set "FLAG=#"
)
echo %%~J-%%I
)
if defined FLAG goto :STOP
)
:STOP
The output is:
Aa-0
Aa-1
Aa-2
Aa-3
Aa-4
Aa-5
Bb-0
Bb-1
Bb-2
Bb-3
Break!
Bb-4
Break!
Bb-5
You will notice that the inner loop finishes execution before the outer one is broken.
The script below breaks the inner loop when a certain condition is net. To not break the outer loop, a sub-routine holding the inner loop and being called (call
) from the outer one is required to hide the code block context of the outer loop from the goto
break-up method:
@echo off
for %%J in (Aa Bb Cc) do (
call :SUB "%%~J"
)
goto :EOF
:SUB
for /L %%I in (0,1,5) do (
if "%~1"=="Bb" if %%I GTR 3 (
echo Break!
goto :STOP
)
echo %~1-%%I
)
:STOP
The output is:
Aa-0
Aa-1
Aa-2
Aa-3
Aa-4
Aa-5
Bb-0
Bb-1
Bb-2
Bb-3
Break!
Cc-0
Cc-1
Cc-2
Cc-3
Cc-4
Cc-5
Here the outer loop finishes its execution without being affected by the broken inner one.
I hope one of the (last two) examples suits the requirements for your script.