Search code examples
windowsfor-loopbatch-filecmdmethod-call

Nested for loop: Storing current screen resolution as a variable for various remote machines using batch script


I need to get current screen resolution of each remote machines (IPs of the same are stored in .txt file) and store it as a variable in the script to be used further.

I am able to iterate through the machines which are in .txt file and I am able to store the screen resolution as a variable but I am not able to do it in a loop for all the machines. Can anyone tell where I am going wrong? How can I use use %%a set in first for in the later code and next for loop as well?

Set MyFile=VMs.txt
rem VMs.txt contains IPs of the machines

for /f "usebackq delims=" %%a in ("%MyFile%") do call :compare
    
:compare
for /f "tokens=2 delims==" %%i in ('wmic /node:"%%a" path Win32_VideoController get CurrentVerticalResolution /value ^| find "="') do set height=%%i
echo %height% 

Solution

  • You try to access the for-loop meta-variable %%a in the called sub-routine :compare, which fails. You could:

    1. Pass %%a as an argument to the sub-routine and access it via %1 there:

       Set "MyFile=VMs.txt"
       rem VMs.txt contains IPs of the machines
      
       for /f "usebackq delims=" %%a in ("%MyFile%") do call :compare %%a
       goto :EOF
      
       :compare
       for /f "tokens=2 delims==" %%i in ('wmic /node:"%~1" path Win32_VideoController get CurrentVerticalResolution /value ^| find "="') do set "height=%%i"
       echo(%height%
      

      The ~-character in %~1 ensures that the passed argument is unquoted (though this might be unneeded here), so there is exactly one pair of quotes around the expression "%~1".

      Note the command goto :EOF, which prevents the code afterwards to become unintentionally executed when the first for /f loop has finished.

      Also note the quoted set syntax, which protects special characters and avoids unintentional trailing white-spaces.

    2. Or ensure that the code in the sub-routine containing %%a runs in the body of a for loop, because for meta-variables are global, but they can only be accessed within for-loop context, which does no longer apply in the sub-routine, even though the call comes from a loop body.

      To re-establish the loop context in the sub-routine, just put the relevant code inside of a for loop that only iterates once:

       Set "MyFile=VMs.txt"
       rem VMs.txt contains IPs of the machines
      
       for /f "usebackq delims=" %%a in ("%MyFile%") do call :compare
       goto :EOF
      
       :compare
       for %%j in (.) do for /f "tokens=2 delims==" %%i in ('wmic /node:"%%a" path Win32_VideoController get CurrentVerticalResolution /value ^| find "="') do set "height=%%i"
       echo(%height%