First, open a command prompt window, run set /?
and read entire help output for command SET on several pages. It explains the usage of delayed expansion on an IF and a FOR example.
It would be most likely also helpful to read the answers on:
How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Your batch file contains setlocal enabledelayedexpansion
at top to enable delayed environment variable expansion. But no environment variable is referenced with syntax !VariableName!
to really make use of delayed environment variable expansion. For that reason "%Element%"
is modified by Windows command processor already on parsing entire command block starting with (
and ending with matching )
to just ""
before executing the command FOR. The environment variable Element
is not defined before FOR command line is reached and cmd.exe
parses the entire FOR command line with the command block ending with )
at end of batch file before executing FOR.
CALL is mainly used to call a subroutine or another batch file from within a batch file. Using CALL on a simple command line can be used to get a command line parsed twice by Windows command processor to avoid usage of delayed expansion. On the first three SET lines it is absolutely not necessary to use CALL as nothing changes on parsing the SET command lines a second time.
First solution is without using delayed expansion by using CALL to double parse the two command lines in code block.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do (
call set "Element=%%ListOFElts[%%I]%%"
call %SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "%%Element%%"
)
endlocal
The definition of environment variable Element
is not necessary in command block as its value is referenced only once. So more compact and therefore faster executed would be:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do call %SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "%%ListOFElts[%%I]%%"
endlocal
There is no command block anymore to execute by FOR on each loop iteration, just a single command line. But it is nevertheless required to use command CALL and use %%ListOFElts[%%I]%%
as the entire FOR command line is parsed already for %VariableName%
references before executing FOR the first time. So "%ListOFElts[%%I]%"
would be replaced already to ""
before FOR is executed at all.
Third solution is with really using delayed expansion.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do (
set "Element=!ListOFElts[%%I]!"
%SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "!Element!"
)
Fourth solution is compact version with using delayed expansion which is similar to the FOR example output by help of command SET:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "ListOFElts[0]=First"
set "ListOFElts[1]=Second"
set "ListOFElts[2]=Third"
for /L %%I in (0,1,2) do %SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\find.exe "!ListOFElts[%%I]!"
endlocal
The command FINDSTR makes it possible to specify multiple search strings.
@%SystemRoot%\System32\whoami.exe /groups /fo list | %SystemRoot%\System32\findstr.exe /L /C:"First" /C:"Second" /C:"Third"
FINDSTR outputs all lines from input stream containing any of the three literally and case-sensitive interpreted strings specified with /C:"..."
. This single command line in a batch file replaces all four batch files above.
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.
call /?
echo /?
endlocal /?
find /?
findstr /?
for /?
set /?
setlocal /?
whoami /?
See also answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? for a detailed explanation why on all SET command lines "variable=value"
is used instead of just variable=value
in the batch files above.