4

This script I wrote is supposed to parse and pull the IP information out of WMIC. The issue is when it is used on a computer with only 1 DNS server entered, the script fails miserably. It appears to run the :remove function even if the variable DNS2 is not set and then the :remove function fails in some way I am not familiar with and ignores the exit command and breaks out of the function and into parts of the script I don't want it in. Here is the offending code, test it by setting your dns servers and index. Script works with 2 DNS servers defined and doesn't with only 1.

@echo off
setlocal enabledelayedexpansion
SETLOCAL ENABLEEXTENSIONS
wmic NICCONFIG where "Index = 1" get /Value | more > storage.txt

for /f "tokens=1-9 delims=,}{=" %%f in (storage.txt) do (
    set cat=%%f
    IF /i !cat!==IPAddress (set IP=%%g)
    IF /i !cat!==IPSubnet (set SUB=%%g)
    IF /i !cat!==DefaultIPGateway (set GW=%%g)
    IF /i !cat!==DNSServerSearchOrder (
        set DNS=%%g
        set DNS2=%%h
    )
    IF /i !cat!==IPEnabled (set enabled=%%g)
    IF /i !cat!==Description (set desc=%%g)
)
if /i %enabled%==True (
if defined IP (
    set item=IP
    CALL :remove
        )
if defined SUB (
    set item=SUB
    CALL :remove
        )
if defined GW (
    set item=GW
    CALL :remove
        )
if defined DNS (
    set item=DNS
    CALL :remove
        )
if defined DNS2 (
    set item=DNS2
    CALL :remove
        )
)
goto :menu
echo SHOULDN'T BE HERE
pause
:::::::::Function to remove quotes::::::::::::::
:remove
for /f tokens^=1^ delims^=^" %%p in (!%item%!) do (
    set !item!=%%p
    rem echo !%item%!
    EXIT /b
    )
echo I BROKE OUT OF THE FUNCTION
pause
:menu
echo I worked!
echo %IP%
echo %SUB%
echo %GW%
echo %DNS1%
if defined DNS2 ( echo %DNS2% )
pause

Here is another example using LotPings rework, note that even though there is not a DNS2, it still executes the bottom "if defined"

@echo off
SETLOCAL ENABLEEXTENSIONS enabledelayedexpansion
Set Prop=IPAddress IPSubnet DefaultIPGateway DNSServerSearchOrder IPEnabled Description
for /f "tokens=1-9 delims=,}{=" %%f in (
  'wmic NICCONFIG where "Index = 1" get /Value^|findstr /i /B "%Prop%"'
) do (IF /i %%f==IPAddress set "IP=%%~g"
      IF /i %%f==IPSubnet  set "SUB=%%~g"
      IF /i %%f==DefaultIPGateway  set "GW=%%~g"
      IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
      )
      IF /i %%f==IPEnabled   set "enabled=%%~g"
      IF /i %%f==Description set "desc=%%~g"
)
set|Findstr /i /B "IP SUB GW DNS Ena Desc"
echo I worked!
echo %DNS%
echo %DNS2%
if defined DNS2 ( echo DNS2 found, shouldn't have found this)
pause
Laser411
  • 43
  • 5
  • The options of the second `for` (tokens, delims) are missing an opening double quote. – Mike Nakis Jan 18 '17 at 22:12
  • @MikeNakis Thats the only proper way to use a double quote as a delimiter. –  Jan 18 '17 at 22:44
  • No, @MikeNakis, they are not; this is an undocumented syntax where several characters are escaped by preceding `^`; the escaped quote `^"` is specified as the delimiter that way... – aschipfl Jan 18 '17 at 22:45
  • I tried to escape the " with ^ to begin with and it did not work. This one does work. Just does not work if DNS2 isn't correctly initialized which is my issue. If DNS2 is taken out completely this script works perfectly. – Laser411 Jan 18 '17 at 23:20
  • @LotPings wow, I did not know that, thanks. – Mike Nakis Jan 19 '17 at 15:17
  • @aschipfl wow, I did not know that, thanks. – Mike Nakis Jan 19 '17 at 15:17

3 Answers3

3

EDIT Complete rework of the batch without temporary file:

@echo off
SETLOCAL ENABLEEXTENSIONS enabledelayedexpansion
Set Prop=IPAddress IPSubnet DefaultIPGateway DNSServerSearchOrder IPEnabled Description
for /f "tokens=1-9 delims=,}{=" %%f in (
  'wmic NICCONFIG where "Index = 1" get /Value^|findstr /i /B "%Prop%"'
) do (IF /i %%f==IPAddress set "IP=%%~g"
      IF /i %%f==IPSubnet  set "SUB=%%~g"
      IF /i %%f==DefaultIPGateway  set "GW=%%~g"
      IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
      )
      IF /i %%f==IPEnabled   set "enabled=%%~g"
      IF /i %%f==Description set "desc=%%~g"
)
If "%DNS2:~3%" EQU "" Set "DNS2="
set|Findstr /i /B "IP SUB GW DNS Ena Desc"
echo I worked!
pause
  • What do you mean aren't assigned anything? What is the new behavior? It is still failing for me but in a different way now. now it is hitting I BROKE OUT once and then hitting I WORKED! twice (Don't ask me how :-/ ) – Laser411 Jan 18 '17 at 23:30
  • I edited the code a little to show more functionality. This code is part of a huge script but I have isolated the problem and stripped it down so that it isn't a handful to read but still demonstrates the issue. The DNS2 variable is needed if there is a second DNS entry (for a secondary DNS server). But the intended function is, 1. Run WMIC and store output 2. Parse output and store IP info in variables 3. Verify that the variables are actually stored and run the :remove function to remove the quotes 4. after all variables have been "cleaned" up, go to menu. – Laser411 Jan 18 '17 at 23:40
  • However, if there is only 1 DNS server, the DNS2 variable is getting messed up somehow and even though it should not be defined, it is still calling the :remove function. When it hit's the remove function with the messed up DNS2 variable something fails and it breaks out of the function where EXIT /b should return it to the end of the "if defined" section and proceed to "goto :menu". – Laser411 Jan 18 '17 at 23:44
  • @Laser411 Take a look at the reworked batch which eliminates the remove function. –  Jan 18 '17 at 23:45
  • Problem with that is there is much more code and that bad DNS2 variable will cause issues elsewhere too. I need to understand why this behavior is happening if there is no second DNS server. This piece of the script is part of a much larger 500 line script which calls DNS2 multiple times. – Laser411 Jan 18 '17 at 23:51
  • @Laser411 wmic output is in Utf16LE, more and findstr convert this - but sometimes there are remnants. In this case DNS2 contains the ´hex codes `0D 0D 0A` Tto eliminate these invalid and invisble chars I added the line `If "%DNS2:~3%" EQU "" Set "DNS2="` –  Jan 19 '17 at 00:01
  • How does that function? And why did my function :remove fail in such a way that it was able to continue but ignore the EXIT command and exit the function? Also, how did you find out that it contained those hex codes? – Laser411 Jan 19 '17 at 00:02
  • BTW, thank you so much for your quick replies and attention. Much appreciated. – Laser411 Jan 19 '17 at 00:12
  • @Laser411 I stumbled about this behaviour before and to rechek I used `Set DNS2>file.txt` and viewed file.txt with a hex dumper. Your remove function failed because for /f removes empty lines and that hex codes are empty lines CR CR LF - so the for falls through. BTW I'd be glad for a vote up and/or answer checked. –  Jan 19 '17 at 00:17
  • I have upvoted you but I don't have enough reputation yet so it doesn't publicly display. Can you explain "%DNS2:~3%" to me? – Laser411 Jan 19 '17 at 00:34
  • @Laser411 It's a substring expression the `:~3` is a zero based position aka 4th place. Pos could be followed by a length arg. See `help set` or visit [ss64.com](http://ss64.com/nt/syntax-substring.html) –  Jan 19 '17 at 00:38
  • If "%DNS2:~3%" EQU "" Set "DNS2=" , isn't working, if defined is still being run. – Laser411 Jan 19 '17 at 00:51
  • @Laser411 strange, tested it here (with index = 0) and it works. What file content do you get when redirecting `set DNS2>file.txt` ? Any hex viewer will do. –  Jan 19 '17 at 01:15
  • Never mind, I was running it in the for loop and not using delayed expansion with !!. Works great, thanks – Laser411 Jan 19 '17 at 04:06
0

When you have such problems you should add debug informations at any relevant points.
In your case add some echo's

IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
        echo #1 "%%~g"
        echo #2 "%%~h"
        if defined dns echo DNS defined
        if defined dns2 echo DNS2 defined
      )

I get something like this

> #1 "10.51.16.9"
> "2 "
> DNS defined
> DNS2 defined

As you can see DNS2 is defined, and the echo #2 "%%~h" shows a destroyed line!
The cause is here, that the line endings of wmic are \r\r\n instead of \r\n.
Therefore in DNS2 is now a single \r character.

You can use a sanitize function to remove all \r from variables.
This works as all \r are removed after a variable expanded by percent signs (but not when it expands by exclamation marks or if it's a %%p parameter)

:sanitize
set "var=!%1!"
set "%1=%var%"
exit /b

And use it by

IF /i %%f==DNSServerSearchOrder (
        set "DNS=%%~g"
        set "DNS2=%%~h"
        call :sanitize DNS
        call :sanitize DNS2
        echo #1 "!DNS!"
        echo #2 "!DNS2!"
        if defined dns echo DNS defined
        if defined dns2 echo DNS2 defined
      )

That's all ...

jeb
  • 78,592
  • 17
  • 171
  • 225
0

Wrap another for /F loop around the one that is parsing the wmic output:

rem // Code before the loop
for /F "delims=" %%e in ('
    wmic NICCONFIG where "Index = 1" get /Value ^| findstr /I /B "%Prop%"
') do (
    for /F "tokens=1-9 delims=,}{=" %%f in ("%%e") do (
        rem // Code inside of the loop...
    )
)
rem // Code after the loop...

The wmic command produced Unicode output, which is not properly converted to ANSI text by the for /F loop, there are some orphaned carriage-return characters left, which disturb the parsing. The additional for /F loop removes those artefacts in a general and reliable way.

aschipfl
  • 33,626
  • 12
  • 54
  • 99