Parsing DHCP output into a CSV

Recently I was involved in moving DHCP from three older domain controllers to three new ones.  This doesn't seem like a daunting task until I realized that they had more than 30 scopes that needed moving.  In order to keep the current settings and proposed changes straight, I wanted to get everything into a spreadsheet.  Unfortunately, Microsoft doesn't provide a simple export tool for DHCP in Server 2003/08.  In Server 2012, DHCP control has been added to the PowerShell family and getting information in and out is vastly simplified.  You can also set up Active/Active scopes in 2012!  Hooray for an easy transition in the future, but not today.  In the meantime we are stuck with netsh, which is still pretty powerful.



There are two commands you can use to get DHCP config information.  The export command will dump the raw data into a file which can be copied to a replacement DHCP server and imported.  This is great if you are doing a straight cut-over, which is not the case here.  The dump command will dump out a text version of the full DHCP config (not including current leases).  This is the information I wanted, but it's not in a format that lends itself to importing into a CSV.  Perl to the rescue!  I learned perl years ago, and I was happily surprised at how quickly it came back to me.  When it comes to simple and easy text manipulation, there's really nothing like it.

[Disclaimer: this script is provided as is.  It's your responsibility to review it for possible issues within your environment.]

So here's the script I wrote to parse that output to a CSV file:
use strict;
use warnings;

#create file i/o variable
open(my $dhcpfile, "<", $ARGV[0]) or die "Can't open dhcpfile.txt";
open(my $results, ">", $ARGV[1]) or die "Can't open dhcpscopes.csv";
my $output = "Name,Network,Subnet,Status,Start,End";

while(<$dhcpfile>) {

if(/add scope/) {
print $output,"\n";
print $results $output,"\n";
my @ln = split(/"/,$_);
my $name = $ln[1];
$name =~ s/,//;
my @info = split(/ /,$ln[0]);
$output = $name.",".$info[5].",".$info[6].",";
}
if(/set state/) {
my $line = $_;
$line =~ s/\s+$//;
my $last = substr($line,-1,1);
#print "Last: ",$last,"\n";
if($last eq "1"){
$output .= "Active,";
}
else  {
$output .= "Inactive,";
}
}
if(/Add iprange/){
my @ln2 = split(/ /,$_);
#print $ln2[7]," ",$ln2[8],"\n";
$output .= $ln2[7].",".$ln2[8];
}
}
#print $output,"\n";
print $results $output,"\n";

In order to use this, you must file get the dump file from the DHCP server. From an elevated command prompt run: netsh dhcp server serverName dump > dhcpfile.txt.  That will create the appropriate text file that the perl script will parse.  Then run the perl script passing it the dhcpfile.txt file and the name of the file you would like the CSV generated as.  The script will parse through the dump file and pull out each scope's name, network, subnet mask, status, and range of IP addresses.  Each row in the CSV will correspond to one of the scopes.  Now you are ready to import this into Excel and work whatever kind of arcane magic might suit you!  It's almost a bit like IPAM, which by the way Server 2012 has an IPAM module built in.  Did you know that?  It's almost like I should write a post of the new networking features of Server 2012...(coming soon).

Once you are ready to configure the new DHCP scopes, you can actually leverage the existing dump files as a batch file.  If you open one of the dump files and look at the contents, each line starts with either a # or dhcp server IPAddress.  I ran a find and replace on all #'s and replaced them with REM.  Then I ran a find and replace on dhcp server IPAddress and prepended netsh to the line.  Then I did a find and replace on the old server IP address and replaced it with the new server's IP address.  Finally, I updated the each scope's IP address range and set the scope as inactive (set state 0 instead of 1).  After a bit of proofreading, I change the txt file to a bat file and ran it on the new server.  Now all of the scopes were added to it's DHCP configuration and set to inactive.  That sure beats doing it through the GUI.

Labels: , , ,