In our organisation, we have two DCHP servers that are running on Windows 2003. It isn’t even an 80-20 configuration. One server is active, and one has all its scopes disabled. Naturally they are supposed to be kept in synch if there are changes made on the primary.
The usefulness of a redundant server might be questioned given the fact that the secondary is sitting in the exact same room in the exact same rack. Anyway, while we are waiting for
Godot a new DHCP management tool to be commissioned by another team, we maintain the legacy DHCP.
Our team needs to update DCHP reservations on pretty much a daily basis. I got a bit tired of connecting to both servers to update the entries, and decided to whip up a quick-and-dirty script to allow entries to be created simultaneously. Since the chances of us getting Powershell installed on the server are zero to none, I did it using a batch file calling
netsh dhcp commands.
My batch file scripting is slightly less good than my Powershell, but it’s nice for a blast from the past occasionally. Once you remember that when you set a variable, there should be no spaces after the = sign. Too much Powershelling, obviously.
One thing to note is that one DCHP scope often covers a number of Class C networks in our environment. Since I couldn’t figure out a way of “guessing” what scope it was from an IP – and compiling lists of literally scores of networks to parse through would take days – this script means that you need to open the DHCP console and get the base IP for the scope you’re adding the record to.
With that in mind, the syntax for the script is:
add-res.cmd [clientIP] [mac] [client] [scopeIP]
The MAC can be formatted as a plain 12-digit hex string, a string divided into blocks of two with dashes (as it would be if you copied it from the output of
ipconfig), or (using the creative syntax of a certain network engineer) in blocks of 4 separated by dots. (I got sick of deleting the stupid dots as well.)
(This shows what happened the first time I saw d1c9.ef19.f1e9 in a job ticket. I am not exaggerating.)
[Client] is simply the computer name (label) you’re associating with the reservation.
When you run the script, it shows the data it will attempt to pass to
netsh and pause to allow time for a last sanity check. When you hit a key, it script connects to both servers and attempts to insert the record. The output of the
netsh dhcp commands comes through to the console, so it’s clear whether it succeeded or failed on either server. It will fail if there is an existing entry for the MAC or IP address in the scope (it won’t blow away an existing entry).
While the MS DHCP console will accept a MAC address formatted as groups of two with dashes in between (and convert it to the simple hex string), it’s a bit fussier with
netsh dhcp – it requires that there are nothing other than hex characters. And of course nothing supports groups of four with dots in between. So most of the script is actually parsing the various possible inputs to get something that will be useful for the MAC address.
I didn’t bother with getting all pedantic about checking to see if the MAC boiled down to 12 hex characters or the IP address was in dotted octets. If someone can’t copy and paste either of those correctly from a job ticket, they deserve for the script to fail.
For the annoying dots, it was surprisingly difficult to find a nice way to parse a variable (from the command arguments) for a certain character/string, and of course that particular character is normally reserved for other purposes in a batch file. There also ain’t no nice
-like commands in batch.
Lines 12 and 13 show where a variable is set to hold the “.”, and then the next line echoes our %2 variable that holds the MAC address to the
findstr command. If it finds the pesky dots, the MAC gets the hack and slash treatment (as do MACs entered with dashes).
Lines 16 and 19 show a traditional way of splitting a string by using
for /f to treat the text as delimited and extract the tokens between the delimiters. So here we’re splitting on the dots or the dashes. If there are no dashes, the string isn’t actually split, and only the
%%a token has something in it – the rest are null (and make no difference when it’s reassembled into the new %mac% variable).
:: Add DHCP reservations to both servers :: Syntax: add-res.cmd [clientIP] [mac] [client] [scopeIP] @echo off if %1.==. GOTO Syntax if %2.==. GOTO Syntax if %3.==. GOTO Syntax if %4.==. GOTO Syntax REM Strip out any dots if MAC is divided into groups of 4 with dots e.g. d1c9.ef19.f1e9 set y=. echo.%2 | findstr /c:%y% 1&>nul if not errorlevel 1 ( for /f "tokens=1-3 delims=." %%a in ("%2") do set mac=%%a%%b%%c ) else ( REM Strip out any dashes - ok if already no dashes in mac for /f "tokens=1-6 delims=-" %%a in ("%2") do set mac=%%a%%b%%c%%d%%e%%f ) echo. echo Adding IP %1 to scope %4 for client %3 with MAC %mac% echo. pause for %%A in (1 2) do ( echo. echo Connecting to \\dhcpsrv%%A netsh dhcp server \\dhcpsrv%%A scope %4 add reservedip %1 %mac% %3 ) goto EOF :Syntax echo. echo Syntax: add-res.cmd [clientIP] [mac] [client] [scopeIP] echo.
As an addendum, if your DHCP scopes are nicely laid out with one scope per Class-C subnet, you can construct a variable for your scope instead of entering it explicitly.
Insert a new line 21 and enter the following code.
for /f "tokens=1-3 delims=." %%a in ("%4") do set scope=%%a.%%b.%%c.0
Delete line 9 and then substitute %scope% for %4 as the variable in lines 22 and 26.