Recently I was approached by a network engineer who was adding scopes to DHCP for our move to Detroit. He had around 80 of them to configure, including all of the different options for the subnets. I did a little research and couldn’t find a native snapin for PowerShell to handle creating the scopes and setting options, but I did know that it could be done via netsh dhcp.
So, I went the second best route and wrote a script that would write a script that would add the scopes for me. The network engineer had a spreadsheet with all of the scopes, their subnet mask, name, and VLANID. Also, for each of the types of scope (data, voice, misc), there were certain DHCP options that had to be set. Those weren’t in the spreadsheet, but he included them in an email and said “for X type, use these settings.”
I can probably improve upon my script by having it look at the spreadsheet for the option values, but this suited our needs and worked pretty well.
The script takes in four parameters.
-csvpath – The path to the CSV file containing the scope info. Since the script uses import-csv, it’s important to make sure that the header columns on the csv are “Subnet” “Mask” “Name” and “VLANID.” MASK should be in a 255.255.255.0 or 255.255.254.0 format (or 253, etc).
-scriptpath – This is the path where you want to output the script file.
-logpath – This is for debugging, but lets you go through in an organized manner to verify the data used to create the netsh script.
-reverseScriptPath – This creates a “delete” script. It’ll go through and remove all fo the subnets you just created…you know, just in case.
It’s worth mentioning that this script is only good for creating scopes with a 24 bit subnet mask. In this case, we were adding to a Class A network with a 24-bit subnet mask. (10.X.Y.0/24) We were adding a bunch of scopes like 10.10.x.0/24. It can easily be modified (by you :) to work for different subnets.
Run this from powershell, use the above arguments, and it’ll give you something to work with. It took about an hour to create the 75 scopes.
Feel free to post questions and your own results!
The output will look like this, but with your IPs and data…obviously…
rem *********************************************
rem Creating script for 3rd Floor North Data
netsh dhcp server 192.168.10.10 add scope 192.168.1.1 255.255.255.0 "3rd Floor North Data"
netsh dhcp server 192.168.10.10 scope 192.168.1.1 add iprange 192.168.1.1 192.168.1.254
netsh dhcp server 192.168.10.10 scope 192.168.1.1 add excluderange 192.168.1.1 192.168.1.10
netsh dhcp server 192.168.10.10 scope 192.168.1.1 add excluderange 192.168.1.225 192.168.1.254
netsh dhcp server 192.168.10.10 scope 192.168.1.1 set optionvalue 003 IPADDRESS 192.168.1.1
netsh dhcp server 192.168.10.10 scope 192.168.1.1 set optionvalue 051 DWORD 691200
netsh dhcp server 192.168.10.10 scope 192.168.1.1 set optionvalue 230 STRING "timeserver=192.168.5.10;timezone=5;dst= -1 8 2 2 1 1 10 2"
netsh dhcp server 192.168.10.10 scope 192.168.1.1 set optionvalue 241 IPADDRESS Vendor="My Vendor Name" 192.168.2.10 192.168.2.11
netsh dhcp server 192.168.10.10 scope 192.168.1.1 set state 1
rem Done creating script for 3rd Floor North Data
rem *********************************************
And here’s the script:
###################################################################################################
#
# PowerShell script to create a batch script that runs netsh dhcp commands to create new scopes
# - Tom Moser
# - Last Modified: 18 June 2010
#
# - Feel free to reuse, modify, and redistribute, but give credit where credit is due
#
# http://www.phishthis.com
#
###################################################################################################
param($csvpath, $scriptpath, $logpath, $reverseScriptPath)
$networks = import-csv $csvpath
#for each line in the csv - I call the imported object "network." Maybe $scope would be better...meh.
foreach($network in $networks)
{
if($network.Name.contains("Data") -or $network.Name.contains("Voice") -eq $false -or $network.Name.contains("Misc") -eq $false)
{
$networktype = "Data"
}
if($network.Name.contains("Voice"))
{
$networktype = "Voice"
}
if($network.Name.contains("Misc"))
{
$networktype = "Misc"
}
#enter your DHCP IP here
$dhcpServerIp = "X.X.X.X"
#put info in to vars
$subnet = $network.subnet
$mask = $network.mask
$name = $network.Name
$vlan = $network.VLANID
#split subnet address in to octets
$octets = $subnet.split('.')
#create a base for the current subnet (a string like 192.168.1)
$subnetBase = "$($octets[0]).$($octets[1]).$($octets[2])"
#create DHCP range start and end - change these to fit your needs
$rangeStart = "$($subnetBase).1"
$rangeEnd = "$($subnetBase).254"
#create DHCP exclusion range - This example will exclude 192.168.0.1 - 20 and 192.168.220 - 250.
#change it to fit your needs. You can also get rid of the exclusionend variable and just have one
#range if that's all you need
$exclusionStart = "$($subnetBase).1 $($subnetBase).10"
$exclusionEnd = "$($subnetBase).220 $($subnetBase).250"
#sets optionvalue 003 - Router. Assumes that you're using X.X.X.1 for your gateway.
$optionValue003 = "$($subnetBase).1"
#I use a switch statement here because I had different option values for each type of scope
#change this as you need. My scope names actually contained the words data, voice, and misc.
switch($networkType)
{
"Data"
{
#option 006 is DNS servers - You don't need to set this if you're setting it on the server options. You can override, though.
$optionValue006 = "X.X.X.X Y.Y.Y.Y Z.Z.Z.Z"
#option 015 is DNS Domain Name - Also not needed, unless you're going to change it from the server options.
$optionValue015 = "domain.forest.root.com"
#option 044 is WINS/NBNS Servers - again, not needed unless different than the server options.
$optionvalue044 = "X.X.X.X Y.Y.Y.Y Z.Z.Z.Z"
#option 046 is WINS/NBT Node Type...same deal as above.
$optionvalue046 = "8"
#dhcp lease time in seconds - this is 8 days
$optionvalue051 = 691200
#option 020 - Timeserver"
$optionvalue230 = "timeserver=X.X.X.X;timezone=5;dst= -1 8 2 2 1 1 10 2"
#this is an example of adding a vendor and IPADDRESS - see the netsh below for details.
$optionvalue241 = "X.X.X.X Y.Y.Y.Y"
}
"Voice"
{
#option 006 is DNS servers
$optionValue006 = "X.X.X.X Y.Y.Y.Y Z.Z.Z.Z"
#option 015 is DNS Domain Name
$optionValue015 = "domain.forest.root.com"
#option 044 - WINS/NBNS Servers
$optionvalue044 = "X.X.X.X Y.Y.Y.Y Z.Z.Z.Z"
#option 046 - WINS/NBT Node Type
$optionvalue046 = "8"
#dhcp lease time in seconds - this is 8 days
$optionvalue051 = 691200
#option 020 - Timeserver"
$optionvalue230 = "timeserver=X.X.X.X;timezone=5;dst= -1 8 2 2 1 1 10 2"
}
"Misc"
{
#optionValue006 is different for the misc scopes
$optionValue006 = "A.A.A.A B.B.B.B"
#optionvalue051 is lease time and set to 8 hours instead of days
$optionvalue051 = 28800
}
}
### output log info - this is just to verify that you wrote out the values you expected. Helps with auditing.
add-content $logpath "`r`n`r`n*********************************************"
add-content $logpath "Creating scope with the following parameters: "
add-content $logpath "Scope name: $name"
add-content $logpath " Address: $subnet"
add-content $logpath " Mask: $mask"
add-content $logpath "ScopeClass: $networkType"
add-content $logpath " VLAN ID: $vlan"
add-content $logpath " Range: $rangeStart to $rangeEnd"
add-content $logpath "Exclusion1: $exclusionStart"
add-content $logpath "Exclusion2: $exclusionEnd"
add-content $logpath " 003: $optionValue003"
add-content $logpath " 006: $optionvalue006"
add-content $logpath " 051: $optionvalue051"
if($networkType -ne "Misc")
{
add-content $logpath " 015: $optionvalue015"
add-content $logpath " 044: $optionvalue044"
add-content $logpath " 046: $optionvalue046"
add-content $logpath " 176: $optionvalue176"
add-content $logpath " 230: $optionvalue230"
}
if($networkType -eq "Data")
{
add-content $logpath " 241: $optionValue241"
}
add-content $logpath "`*********************************************"
#### end logging
#### create script
# This is where we actually write out all of the netsh commands
# you need to run this from your DHCP server.
add-content $scriptpath "rem *********************************************"
add-content $scriptpath "rem Creating script for $name"
#add scope
add-content $scriptpath "netsh dhcp server $dhcpServerIp add scope $subnet $mask `"$name`""
#add distribution range
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet add iprange $rangeStart $rangeEnd"
#add exclusion range 1
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet add excluderange $exclusionStart"
#add exclusion range 2 - remove this if you don't have a second exclusion range
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet add excluderange $exclusionEnd"
#set scope option 003 - Router
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 003 IPADDRESS $optionValue003"
#this sets the different DNS servers for the Misc scopes
if($networkType -eq "Misc")
{
#set scope option 006 - DNS Servers
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 006 IPADDRESS $optionValue006"
}
#set dhcp option 051 - DHCP Lease length
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 051 DWORD $optionvalue051"
#these are only set on the data or voice scopes - not on misc.
if($networkType -ne "Misc")
{
#the first three are commented because they aren't needed unless you're overriding the DHCP server options.
#set scope option 015 - domain Name
#add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 015 STRING $optionvalue015"
#set scope option 044 - WINS/NBNS
#add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 044 IPADDRESS $optionValue044"
#set scope option 046 - Wins/NBNS - 0x8
#add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 046 BYTE $optionvalue046"
#set scope option 230 OnTimeClock
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 230 STRING `"$optionvalue230`""
}
#again, only for data
if($networkType -eq "Data")
{
#this is an example of how to set IPs and a vendor class on a scope option
#the syntax is optionvalue XXX IPADDRESS Vendor=vendor name XXX.XXX.XXX.XXX YYY.YYY.YYY.YYY
#set scope option 241 Option43
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set optionvalue 241 IPADDRESS Vendor=`"My Vendor Name`" $optionvalue241"
}
#activate scope
add-content $scriptpath "netsh dhcp server $dhcpServerIp scope $subnet set state 1"
#this creates the deletion script - just in case you bork a parameter and need to delete and start over
#you could also use the script to create a fix, but this might be easier
add-content $reverseScriptPath "netsh dhcp server $dhcpServerIp delete scope $subnet"
add-content $scriptpath "rem Done creating script for $name"
add-content $scriptpath "rem *********************************************`r`n"
#you're done! Depending on the number of scopes you create, it can take some time. The 75 or so scopes I created took around 30 minutes.
}

