1

I currently work in a distillery that mostly uses an ethernet based controls network that is dedicated for all automation equipment. To help save time, I created a batch file for each system at the distillery to be able to quickly change my computer's IP address when I am at different parts of the plant. I created this directory of batch files and placed them on our server so that our maintenance guys can access them. While this works good, it came to my mind that if multiple people attempt to go online in this manner that there will be conflicting IP addresses on the network.

I attempted to modify my batch file(s) to first ping an IP address (10.120.194.254) then based on the result, either alter the IPv4 "Local Area Connection" to that IP address or continue to the next available IP address (10.120.194.253)... (10.120.194.252)... and so on. My ideal goal is to perform this same procedure for 5 IP addresses then if all are unsuccessful, present a dialog box that displays a message to check the number of users on the network. Typically, IP addresses xxx.xxx.xxx.250-254 are used for programming on a network so this is the reasoning behind this. The probability of this many users on a network is low but it would be a nice feature to have for that "just in case scenario".

Below is my code for the original batch file to change the IP address for IPv4 "Local Area Connection".

@echo off
netsh interface IPv4 set address name="Local Area Connection" static 10.120.194.254 255.255.255.0

@echo off
netsh interface IPv4 set dns name="Local Area Connection" source=dhcp

I tried using the errorlevel function but could not get consistent results when pinging the network. Furthermore, every time I ping an address it polls 4 times then moves on to the next one. Is there a way to shorten this poll time? Below is my code for the batch file that I have been trying to get to work:

@echo off

ping "10.120.194.254"

IF %errorlevel%==0 GOTO IP_Attempt2
    @echo off
    netsh interface IPv4 set address name="Local Area Connection" static 10.120.194.254 255.255.255.0
    @echo off
    netsh interface IPv4 set dns name="Local Area Connection" source=dhcp
    exit /b

:IP_Attempt2

ping "10.120.194.253"

IF %errorlevel%==0 GOTO IP_Attempt3
    @echo off
    netsh interface IPv4 set address name="Local Area Connection" static 10.120.194.253 255.255.255.0
    @echo off
    netsh interface IPv4 set dns name="Local Area Connection" source=dhcp
    exit /b

:IP_Attempt3

ping "10.120.194.252"

IF %errorlevel%==0 GOTO IP_Attempt4
    @echo off
    netsh interface IPv4 set address name="Local Area Connection" static 10.120.194.252 255.255.255.0
    @echo off
    netsh interface IPv4 set dns name="Local Area Connection" source=dhcp
    exit /b

:IP_Attempt4

ping "10.120.194.251"

IF %errorlevel%==0 GOTO IP_Attempt5
    @echo off
    netsh interface IPv4 set address name="Local Area Connection" static 10.120.194.251 255.255.255.0
    @echo off
    netsh interface IPv4 set dns name="Local Area Connection" source=dhcp
    exit /b

:IP_Attempt5

ping "10.120.194.250"

IF %errorlevel%==0 GOTO Max_IP_Attempts
    @echo off
    netsh interface IPv4 set address name="Local Area Connection" static 10.120.194.250 255.255.255.0
    @echo off
    netsh interface IPv4 set dns name="Local Area Connection" source=dhcp
    exit /b

:Max_IP_Attempts

echo Max attempts have been made with this batch file. Verify users on the network.
pause
exit /b

I have attached a snapshot of the CMD prompt window after running the batch file: IP Address snapshot

Clijsters
  • 4,031
  • 1
  • 27
  • 37
AGardner
  • 11
  • 1
  • 2
  • A long time ago I wrote a [script](https://stackoverflow.com/a/40964527) that performs several pings concurrently, perhaps it helps you... – aschipfl May 05 '20 at 21:55
  • And if you want to ping a whole /8 subnet: `set ip=192.168.0 for /L %%N IN (1, 1, 254) DO (ping %ip%.%%N -n 1 -w 1 | find "TTL" && echo %ip%.%%N >> ips.txt)` could do the trick. – Clijsters May 06 '20 at 09:00
  • You need to have a valid IP address in order to use ping. You need to have already solved your problem of finding an unused IP address in order for this to be available. – Damien_The_Unbeliever May 06 '20 at 09:21

2 Answers2

2

From https://ss64.com/nt/ping.html:

A successful PING does NOT always return an %errorlevel% of 0 Therefore to reliably detect a successful ping, pipe the output into FIND and look for the text "TTL".

In your instance, you'll want to pipe the output of FIND into a variable with a FOR loop. If FIND does not find "TTL" in the output text, the variable will not be defined. You can check for whether the variable is defined or not to define your outcome (either move to the next IP or set the current IP as the local address). In your script, this can look something like this:

FOR /F "delims=" %%f IN ('ping "IP" ^| find "TTL"') DO (SET tempVar=%%f)
IF NOT DEFINED tempVAR netsh interface IPv4 set address name="Local Area Connection" static IP 255.255.255.0 & netsh interface IPv4 set dns name="Local Area Connection" source=dhcp & EXIT /B
GOTO IP_Attempt$

In the first line, | pipes the output of ping into the find command (| is escaped with a caret). The second line is a re-implementation of your IF statement. & will link the commands together so that they can be processed in the same IF clause. If the IF clause doesn't match, the third line will GOTO your next label.

Furthermore, every time I ping an address it polls 4 times then moves on to the next one. Is there a way to shorten this poll time?

Try ping -n 1 target_IP. It will only ping once before moving on. For most built-in commands, you can get a satisfactory printout of functionality by trying [command] /? in CMD.

SS64, DosTips, and the Wikibooks page on batch scripting are also good references to have around if you ever get stuck.

Hope this helps. This is my first contribution as well, so please feel free to ask if I left something unclear (or if you have additional questions).

Clijsters
  • 4,031
  • 1
  • 27
  • 37
  • You should do `set "tempVar="` at the beginning to ensure it is definitely not defined. Anyway, you can do this way simpler when you query the `ErrorLevel` of `find` which returns `0` if `TTL=` is found (yes, the `=` should be included) and `1` otherwise: `if ErrorLevel 1 netsh ...`. Or you can use [conditional execution operators](https://ss64.com/nt/synta-redirection.html): `ping "IP" | find "TTL=" || netsh ...`... – aschipfl May 05 '20 at 21:26
  • Hello and welcome to StackOverflow. This looks like a good first contribution to me. I edited some of your formatting and I suggest you to move the last paragraph into the comments section, as it's not an essential part of your answer. – Clijsters May 06 '20 at 08:56
  • I attempted to use your sample code but did not have much luck. I copied the For instruction twice using the next IP address available IP address in my list. The first IP address pinged successfully and got a reply with a TTL value of 128. The next For instruction did not ping successfully and instead of setting the IP address the instruction proceeded to the next label where I had a pause to check the overall operation of the batch file. The For instructions I have been seeing all reference a .txt file which is not what I wish to do. Is there an easier way to look for the presence of "TTL"? – AGardner May 27 '20 at 21:19
0

Reading your question looks like it boils down to the question:

How can I find used or free IP Addresses in my subnet using windows batch files?

And the answer consists basically of three lines of code plus some explanations:

if exist ips.txt del ips.txt > nul

echo Please enter the first 24 bits of your subnet (e.g. 192.168.0):
set /p ip=

for /L %%N IN (1, 1, 254) DO (
    echo pinging %ip%.%%N
    ping %ip%.%%N -n 1 -w 1 | find "TTL" && echo %ip%.%%N >> ips.txt
)

cls
type ips.txt

Every IP which responds to a single ping is written to ips.txt. That's your "don't use"-list. You could easily customize this snippet to work automatically every n minutes and without user input or to output free ips and ignore used ones.

If you want to set the ip address automatically after your script found a free one, use netsh interface ip set address "LAN" static %ip% %subnet% %gateway%. For further information on using netsh you might want to read assign the ip address by the using the batch file or How to change ip address using script on windows.


While this approach may fit your needs perfectly, it should be considered to use DHCP-based ip-management or fixed IPs for every station. But that's not the StackOverflow-Part of your question. Help regarding networking and infrastructure management can be found on other communities.

Clijsters
  • 4,031
  • 1
  • 27
  • 37