How to handle multiple 'for' statements in a batch file?

757 views Asked by At

I am attempting to create a batch file which will take a list of users from a text file, run a dsquery against Active Directory to determine if the account has been disabled or not, and then output the results to a different text file containing the user ID and the status (yes/no) of whether they've been disabled or not.

I feel like I'm positioning the quotes or the parentheses incorrectly but I'm also not 100% sure if multiple 'for' statements can even be nested like this. Input much appreciated.

for /f "tokens=1" %%G in (termlist.txt) do (
for /f "Tokens=*" %%a in ('dsquery user -samid %%G^|dsget user -disabled^| Find /v "disabled"^| Find /v "dsget succeeded"') do set disable=%%a)
echo "%%G %disable%" >> termvalid.txt)
3

There are 3 answers

1
RGuggisberg On BEST ANSWER
  1. You left out the space in front of each instance of the ^ character.
  2. Your entire FOR construct is loaded as one line (regardless of how many physical lines it occupies)... so %disable% is expanded at the time the entire construct is loaded and will not change at run time. You could enable delayed expansion, but there is no need for that in this case.

Try this (use first line if you want to be sure you are not appending to an old unwanted file):

if exist termvalid.txt del /f /q termvalid.txt
for /f "tokens=1" %%G in (termlist.txt) do (
   for /f "Tokens=*" %%a in ('dsquery user -samid %%G ^|dsget user -disabled ^| Find /v "disabled" ^| Find /v "dsget succeeded"') do echo "%%G %%a" >> termvalid.txt))
0
Aacini On

There is an easy method to check that several nested commands have the right number of parentheses. Just indent each nested command three spaces to the right, place the opening left parentheses in the same line, and place the closing right parentheses in the same column of the command that it closes. For example

for %%a in (set) do (
   for %%b in (set) do (
      if %%a equ %%b (
         then part
      ) else (
         else part
      )
   )
)

When I apply such format to your code, I got this:

for /f "tokens=1" %%G in (termlist.txt) do (
   for /f "Tokens=*" %%a in ('dsquery user -samid %%G^|dsget user -disabled^| Find /v "disabled"^| Find /v "dsget succeeded"') do set disable=%%a
)
echo "%%G %disable%" >> termvalid.txt)

This way, it is now evident that there is an additional right parentheses (that is ignored), but that the %%G is placed outside its FOR. There are two ways to fix this problem; eliminating the right parenteses and move the ECHO to the right place:

for /f "tokens=1" %%G in (termlist.txt) do (
   for /f "Tokens=*" %%a in ('dsquery user -samid %%G^|dsget user -disabled^| Find /v "disabled"^| Find /v "dsget succeeded"') do set disable=%%a
   echo "%%G !disable!" >> termvalid.txt
)

... or insert the missed left parentheses:

for /f "tokens=1" %%G in (termlist.txt) do (
   for /f "Tokens=*" %%a in ('dsquery user -samid %%G^|dsget user -disabled^| Find /v "disabled"^| Find /v "dsget succeeded"') do (
      set disable=%%a
   )
   echo "%%G !disable!" >> termvalid.txt
)

... besides of the problem that %disable% must be accessed via delayed !variable! expansion, because it is inside a FOR command.

1
SomethingDark On

Nested for loops are perfectly valid. However, you need to make sure that none of the token variables will overlap.

for /f "tokens=1,2" %%A in ("hello world") do echo %%A

uses both %%A and %%B (because of the tokens=1,2) even though only %%A is declared and explicitly used, so the next safe variable to use is %%C. That said, for variables are case sensitive so you can use %%A through %%Z and %%a through %%z, which means that the way you have it in your code will work fine (and it would also work fine if you used %%A, as long as the inner for loop didn't create more than 6 tokens).