0

This batch file loops through a list of computer IP addresses and passwords with a comma separator (IP_List.txt). Commands are then run to connect remotely to each computer. I've got another list of IP's which are exceptions and need to be skipped, so I've got a variable (set str=) which lists these IP's and I'm using findstr to search for them:

@ECHO OFF
setlocal EnableDelayedExpansion
Pushd "%~dp0"
Set Log=LogFile.log
set str=172.16.66.1 172.16.66.2 172.16.66.3 172.16.66.4
FOR /F "tokens=1,2 delims=," %%i in (IP_List.txt) do call :process %%i %%j
(ECHO+ & ECHO --- END OF REPORT ---) >> %Log%
GOTO :EOF
:process
set IP=%1
set PW=%2
@ECHO %IP% | findstr "%str%" >nul
IF NOT ERRORLEVEL 1 (ECHO+ & ECHO %IP% & ECHO This IP address was skipped) >> %Log% & GOTO :EOF
@ECHO Processing %IP% >> %Log%

---- (remainder of batch file here) ----

There was a problem with findstr in that having 172.16.66.2 on the exception list, findstr was mistakenly finding a match with the following IP's on my overall list: 172.16.66.224, 172.16.66.225, 172.16.66.226, etc.

After changing the code and putting the list of IP exceptions in a text file (IP_Exceptions.txt) I was able to get past the findstr problem and this modified batch file works without issue:

@ECHO OFF
setlocal EnableDelayedExpansion
Pushd "%~dp0"
Set Log=LogFile.log
FOR /F "tokens=1,2 delims=," %%i in (IP_List.txt) do call :process %%i %%j
(ECHO+ & ECHO --- END OF REPORT ---) >> %Log%
GOTO :EOF
:process
set IP=%1
set PW=%2
::~~ Add a right bracket to the end of the IP address variable
SET IPstr=%IP%]%x%
set match=N
::~~ Loop through a list of IP address exceptions
::~~ (A left bracket has been added to the beginning of
::~~ each IP on the list in order to use it as a delimiter)
::~~ Add a right bracket to the end of the variable "%%j"
::~~ in order to look for a match with the findstr command
for /F "delims=[" %%i in (IP_Exceptions.txt) do (
 for /F "tokens=1" %%j in ("%%i") do (
  ECHO %%j] | findstr "%IPstr%" >nul
  IF not errorlevel 1 set match=Y
 )
)
IF %match% == Y (ECHO+ & ECHO %IP% & ECHO Skipped this machine) >> %Log% & GOTO :EOF
@ECHO Processing %IP% >> %Log%

:: ---- (remainder of batch file here) ----

The specifics of getting the findstr section to work correctly without false matches (adding brackets to variables, nested for loops with delimiters, etc.) was kind of clumsy though. Any suggestions on making that section more efficient would be greatly appreciated.

  • 1
    So why not use the `/G` option with `FINDSTR` instead? – Squashman Jul 06 '20 at 16:53
  • There is a [bug with multiple search strings](https://stackoverflow.com/questions/8921253/why-doesnt-this-findstr-example-with-multiple-literal-search-strings-find-a-mat/8921279#8921279) with the `FINDSTR` command. – Squashman Jul 06 '20 at 16:58
  • 2
    The `.` is a special meta-character to `findstr` meaning *any character*, so you should add the `/L` switch to force literal search strings… – aschipfl Jul 06 '20 at 17:07
  • @Squashman, this should (hopefully) not be relevant since the sample search strings are of equal lengths; even if they were not, you could alyway add the `/I` option, which does not change anything here except for preventing the said bug… – aschipfl Jul 06 '20 at 17:09
  • 1
    I just found the root cause and it has nothing to do with there being more than four IP's on the exception list. The problem is, one of the IP's on the full exception list is 172.16.66.2. What happens is the IP's 172.16.66.225 and 172.16.66.226 end up getting mistakenly skipped. I've been trying different findstr switches but still haven't figured out how to fix this. – sysadmin0105 Jul 06 '20 at 18:26
  • @sysadmin0105, Open a Command Prompt window, type `help findstr`, or `findstr /?`, press the `[ENTER]` key, and take a look at he usage options. I might even ask you to pay particular attention to the word position meta-characters. However in doing so, you'll be ignoring the previous correct advice, that your `.` characters are not being used as periods, but as a meta-character itself. That means you could get false positives because a period would be treated the same as a number. – Compo Jul 06 '20 at 22:17
  • A simple option, without changing the content of your text file, might be to use `findstr "%str%#"` where `#` can be of your considered choosing, and used earlier in the code, like this, `set IP=%1#`. or before that here, `call :process %%i# %%j`. This would mean that you could then use the `/L` option to maintain the `.` characters literal meaning, `findstr /L "%str%#"`. – Compo Jul 06 '20 at 22:38
  • Instead of using the variable "str" for the list of IP exceptions I put them in a text file (IP_Exceptions.txt). My modified batch file works and I've posted it as an answer here. Other than looping through a text file of the exceptions which is a better way to go, the code I used to get past the findstr problem is kind of a clumsy solution. There's got to be a cleaner way of doing this. Any suggestions? – sysadmin0105 Jul 06 '20 at 22:41
  • There is a cleaner way, but your question was looking for a fix for the way you were doing it, not asking for someone to code you a better way. Would you like to edit your question, by deleting your answer, and adding it as an update to your question, along with modified content? You could then ask for assistance with making it more efficient if you have an idea how your current implementation is letting the code down. – Compo Jul 06 '20 at 22:46
  • @Compo I just edited the question and added the modified batch file to the body of the post. Can't figure out how to delete my answer though.... when I click delete I get a prompt that says "Delete this post?" I don't want to delete the whole post, just my answer. – sysadmin0105 Jul 06 '20 at 23:28
  • @sysadmin0105: your question and your answer are two different posts. – Stephan Jul 07 '20 at 07:06

2 Answers2

0

A modified batch file works but it's clumsy:

@ECHO OFF
setlocal EnableDelayedExpansion
Pushd "%~dp0"
Set Log=LogFile.log
FOR /F "tokens=1,2 delims=," %%i in (IP_List.txt) do call :process %%i %%j
(ECHO+ & ECHO --- END OF REPORT ---) >> %Log%
GOTO :EOF
:process
set IP=%1
set PW=%2
::~~ Add a right bracket to the end of the IP address variable
SET IPstr=%IP%]%x%
set match=N
::~~ Loop through a list of IP address exceptions
::~~ (A left bracket has been added to the beginning of
::~~ each IP on the list in order to use it as a delimiter)
::~~ Add a right bracket to the end of the variable "%%j"
::~~ in order to look for a match with the findstr command
for /F "delims=[" %%i in (IP_Exceptions.txt) do (
 for /F "tokens=1" %%j in ("%%i") do (
  ECHO %%j] | findstr "%IPstr%" >nul
  IF not errorlevel 1 set match=Y
 )
)
IF %match% == Y (ECHO+ & ECHO %IP% & ECHO Skipped this machine) >> %Log% & GOTO :EOF
@ECHO Processing %IP% >> %Log%

:: ---- (remainder of batch file here) ----
0

Your subroutine could look like this:

...
:process
echo/ %str% |findstr /LC:" %1 " >nul && (
  echo %1 skipped
  goto :eof
)
echo processing %1 with %2
:: ---- (remainder of batch file here) ----

Note that I reversed the "search" logic (to make it easier to process spaces correctly)
Instead of echo <sub>|findstr <whole>, I switched to echo <whole> |findstr <sub>

Note: the spaces in echo/ %str% |findstr /LC:" %1 " are critical (they are also compared to avoid false positives).

/LC: tells findstr to search literal (treating the dot as a dot instead of a wildcard) and including spaces.

Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Sorry for any confusion but the problem was not related to findstr treating the dot as a dot instead of a wildcard. After my initial post I had to edit it a couple times in order to clarify exactly what the problem was, and how my modified batch file solved it. The problem was the false positives findstr was coming up with due to the IP 172.16.66.2 being on the exceptions list. This has been solved with my new batch file and at this point I'm just looking for a more elegant solution than the one I came up with. – sysadmin0105 Jul 07 '20 at 12:07
  • Yes, I understood that. My code takes care of those false positives (taking care of the dots with `/L` is a mere "bonus") – Stephan Jul 07 '20 at 12:45
  • Guess I'm in the bonus round. Your code worked great, thanks. Very clever using spaces in the search string to avoid false positives. About the "echo/".... don't know what the slash does exactly, I've never seen that before, can't find it documented anywhere. And I know /L and /C are separate findstr switches but I didn't know they can be combined like that. Can't find that documented anywhere. – sysadmin0105 Jul 07 '20 at 13:41
  • [You're welcome](https://stackoverflow.com/help/someone-answers). The `/` is just to [make echo more reliable](https://www.dostips.com/forum/viewtopic.php?t=774). In this case, it's merely to make the additional space very visible. And now that you mention it - I also haven't seen the `findstr` switches behavior in any (official) documentation. But by now I'm so used to it, I don't even think about it. – Stephan Jul 07 '20 at 13:56