The DHCP role on Windows Server is five minutes of work and one gotcha that eats an afternoon if you miss it: an unauthorised DHCP server in a domain hands out exactly zero leases, silently. Install it, authorise it, scope it — all from PowerShell, no wizard.
TL;DR:
Install-WindowsFeature DHCP -IncludeManagementTools
netsh dhcp add securitygroups
Restart-Service dhcpserver
Add-DhcpServerInDC -DnsName dhcp01.lab.example.com -IPAddress 10.0.0.5
Add-DhcpServerv4Scope -Name "LAN" -StartRange 10.0.0.100 -EndRange 10.0.0.200 -SubnetMask 255.255.255.0
Set-DhcpServerv4OptionValue -ScopeId 10.0.0.0 -Router 10.0.0.1 -DnsServer 10.0.0.5 -DnsDomain lab.example.com
That's a working server. Details and the gotchas below.
Install the role
Install-WindowsFeature DHCP -IncludeManagementTools
-IncludeManagementTools pulls in the DHCP console and the PowerShell module. Skip it and you've installed a service you can't manage without a second command. No reboot needed.
The host needs a static IP before you go further. A DHCP server pulling its own address from another DHCP server is a circular mess — if you've just run through the initial setup checklist the static IP is already done.
Post-install: security groups and the post-deploy step
Two things Server Manager nags you about after install. Do them in PowerShell instead:
netsh dhcp add securitygroups
Restart-Service dhcpserver
This creates the local DHCP Administrators and DHCP Users groups and restarts the service to pick them up. Without it the service runs, but delegated admin won't work.
In the GUI there's a yellow "post-deployment configuration" notification that also marks the install as complete. The PowerShell equivalent flips a registry flag:
Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\ServerManager\Roles\12 `
-Name ConfigurationState -Value 2
Purely cosmetic — it stops Server Manager pestering you. The server hands out leases regardless. I set it so the dashboard is green and the next admin doesn't think the install was abandoned half-way.
Authorise in AD — the classic gotcha
Add-DhcpServerInDC -DnsName dhcp01.lab.example.com -IPAddress 10.0.0.5
This is the one that wastes the afternoon. In an Active Directory domain, a DHCP server must be authorised in AD before it will respond to a single DISCOVER. No error in the GUI, no obvious log entry — clients just sit there with APIPA 169.254.x.x addresses and you start blaming the switch.
The mechanism is deliberate: it stops a rogue DHCP server (someone's home router plugged into the LAN) from poisoning the network. Authorisation requires Enterprise Admin rights, because the record lives in the configuration partition of the forest.
Check what's authorised:
Get-DhcpServerInDC
The exception: a standalone (workgroup) DHCP server doesn't need authorisation and Add-DhcpServerInDC will fail with no DC to talk to. That's fine — workgroup DHCP just works once the scope is active. Authorisation is an AD-only concept. If you're authorising, the host should already be joined to the domain, ideally next to your first domain controller.
Create a scope
Add-DhcpServerv4Scope -Name "LAN" `
-StartRange 10.0.0.100 -EndRange 10.0.0.200 `
-SubnetMask 255.255.255.0 `
-State Active
The ScopeId is derived from the range and mask — here it's 10.0.0.0, and you reference it by that ID in every later command. The start/end range is the pool that gets handed out, not the whole subnet. Leave room below .100 and above .200 for static kit: gateways, switches, the DHCP server itself, printers you don't want chasing leases.
-State Active matters. Create a scope without it and it sits InActive, serving nothing, with no warning louder than a different colour in the console.
Scope options — router, DNS, domain
Set-DhcpServerv4OptionValue -ScopeId 10.0.0.0 `
-Router 10.0.0.1 `
-DnsServer 10.0.0.5 `
-DnsDomain lab.example.com
These are the three options that actually matter day to day:
| Option | Cmdlet flag | What it sets |
|---|---|---|
| 003 | -Router |
Default gateway |
| 006 | -DnsServer |
DNS server(s) clients use |
| 015 | -DnsDomain |
DNS suffix appended to hostnames |
In a domain, option 006 must point at your DCs, not a public resolver like 1.1.1.1. Domain-joined clients that resolve through public DNS can't find _ldap._tcp SRV records and Group Policy quietly stops applying. This is a top-three cause of "GPO isn't working" tickets.
Set options at the server level (-ScopeId omitted, or via Set-DhcpServerv4OptionValue without a scope) for defaults that apply everywhere; set them per-scope to override. Per-scope wins.
Reservations — pin a MAC to an IP
Add-DhcpServerv4Reservation -ScopeId 10.0.0.0 `
-IPAddress 10.0.0.150 `
-ClientId "AA-BB-CC-DD-EE-FF" `
-Description "office-printer"
-ClientId is the MAC. Dashes or no separators both parse; colons do not — AA-BB-CC-DD-EE-FF or AABBCCDDEEFF, never AA:BB:.... The reserved IP must sit inside the scope range or the reservation never fires.
Reservations beat static IPs on the device for anything that supports DHCP: change a subnet once on the server instead of touching every printer and NAS by hand. List them:
Get-DhcpServerv4Reservation -ScopeId 10.0.0.0
Exclusions — carve holes in the pool
Add-DhcpServerv4ExclusionRange -ScopeId 10.0.0.0 `
-StartRange 10.0.0.100 -EndRange 10.0.0.110
Use this when you want a scope to cover a wide range but keep a block free for static assignment — e.g. you scoped .100–.200 but want .100–.110 reserved for servers you'll address by hand. Excluded addresses are never offered, even though they're inside the pool.
Lease duration and conflict detection
Set-DhcpServerv4Scope -ScopeId 10.0.0.0 -LeaseDuration 8.00:00:00 # 8 days
Set-DhcpServerSetting -ConflictDetectionAttempts 1
Default lease is 8 days — fine for a stable office. Drop it to a few hours on guest/transient networks where devices churn, so the pool recycles fast. Don't go below an hour on a busy LAN or you'll flood the server with renewals.
Conflict detection makes the server ping an address before offering it. Off by default (zero attempts) for speed. Set it to 1 or 2 if you've got static IPs squatting inside the pool and want to avoid handing out a duplicate. It adds latency to every lease, so leave it at 0 on a clean network.
Failover — redundancy in two commands
One DHCP server is a single point of failure: it dies, leases expire, the LAN goes dark. Modern Windows Server does this properly with DHCP failover — no more manual 80/20 split-scope juggling.
Add-DhcpServerv4Failover -Name "LAN-failover" `
-PartnerServer dhcp02.lab.example.com `
-ScopeId 10.0.0.0 `
-LoadBalancePercent 50 `
-SharedSecret (Read-Host -AsSecureString)
Both servers serve the same scope, sync lease state, and cover for each other. LoadBalance mode splits active load 50/50; HotStandby mode keeps the partner idle until the primary drops. The partner needs the DHCP role installed and authorised first — failover replicates the scope config for you, so you don't recreate it by hand.
Verify
Get-DhcpServerInDC # authorised?
Get-DhcpServerv4Scope # scope active?
Get-DhcpServerv4OptionValue -ScopeId 10.0.0.0 # options set?
Get-DhcpServerv4Lease -ScopeId 10.0.0.0 # anyone leasing?
If Get-DhcpServerv4Lease returns rows with real hostnames, you're done. Empty on a live network means clients aren't getting offers — work back up the list.
Gotchas
- No leases, no error, in a domain — almost always missing
Add-DhcpServerInDC. CheckGet-DhcpServerInDCfirst, every time. - Scope created but dead —
StateisInActive. Set-State ActiveorSet-DhcpServerv4Scope -State Active. - GPO stops applying after DHCP changes — option 006 points at a public DNS instead of your DCs. Domain clients need domain DNS.
- Reservation ignored — colon-separated MAC, or the reserved IP sits outside the scope range. Both fail quietly.
- Two DHCP servers, intermittent wrong gateway — you stood up a second server without failover and both are answering independently. Use
Add-DhcpServerv4Failover, not two parallel scopes. Add-DhcpServerInDCerrors on a workgroup box — expected, there's no AD. Standalone DHCP needs no authorisation; ignore it.
Five commands to a working server, one of which everyone forgets. Authorise in AD first and the rest is plumbing.