
Automate DHCP Lease Reporting on Windows Server
Before you run this
This guide builds a read-only PowerShell script that enumerates your DHCP scopes, pulls the current IPv4 leases from each, writes them to a timestamped CSV, and (optionally) emails the file. It does not change any DHCP configuration — no scopes, reservations, options, or leases are created, modified, or deleted. The worst it can do is fill a disk with CSVs if you never prune them.
Privileges: Reading DHCP data requires membership in the DHCP Administrators or DHCP Users group on the server, or local Administrator. When you later register this as a scheduled task, the task's run-as account needs that same read access. The DhcpServer PowerShell module is present automatically when the DHCP Server role is installed; to run it from an admin workstation instead you need the RSAT: DHCP Server Tools feature.
Test first: run the script interactively and read its output before you schedule anything. On a busy server Get-DhcpServerv4Lease across many large scopes can take a while and hit the DHCP database, so run it once by hand, confirm it completes and the CSV looks right, then automate. Nothing here is destructive, so there is no undo to worry about for the data — the only thing you'll want to reverse is the scheduled task itself, which I cover at the end.
Assumptions: Windows Server 2019 or 2022 with the DHCP role installed, run locally on the DHCP server, Windows PowerShell 5.1 (the version shipped in-box), domain-joined. IPv4 only. If your estate is IPv6, the parallel cmdlets use the v6 suffix (Get-DhcpServerv6Scope, Get-DhcpServerv6Lease) but I'm not walking through those here.
The reporting script
Save this as C:\Scripts\Export-DhcpLeases.ps1. Replace C:\Reports\DHCP with wherever you want the CSVs to land.
#requires -Modules DhcpServer
# --- Settings you edit ---
$ReportRoot = 'C:\Reports\DHCP' # output folder - change to suit
$KeepDays = 30 # delete CSVs older than this
# -------------------------
# Make sure the output folder exists
if (-not (Test-Path $ReportRoot)) {
New-Item -Path $ReportRoot -ItemType Directory -Force | Out-Null
}
$stamp = Get-Date -Format 'yyyy-MM-dd_HHmm'
$csvPath = Join-Path $ReportRoot "DHCP-Leases_$stamp.csv"
# Pull every active IPv4 scope, then every lease inside it.
$leases = foreach ($scope in Get-DhcpServerv4Scope) {
Get-DhcpServerv4Lease -ScopeId $scope.ScopeId |
Select-Object `
@{Name='ScopeName'; Expression={ $scope.Name }},
ScopeId,
IPAddress,
HostName,
ClientId, # the MAC / client identifier
AddressState, # Active, Declined, Expired, etc.
LeaseExpiryTime,
Description
}
# Write the report. UTF8 keeps hostnames with odd characters intact.
$leases | Sort-Object ScopeId, IPAddress |
Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
Write-Host "Wrote $($leases.Count) leases to $csvPath"
# Housekeeping: remove reports older than $KeepDays
Get-ChildItem -Path $ReportRoot -Filter 'DHCP-Leases_*.csv' |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$KeepDays) } |
Remove-Item -Force
A few notes on the non-obvious parts:
#requires -Modules DhcpServermakes the script fail fast with a clear message if it's run somewhere the module isn't available, rather than erroring cmdlet-by-cmdlet.ClientIdis the client's hardware/identifier string as DHCP stores it.AddressStateis the lease state — filter onActivelater if you only care about live leases.- The property names above (
ScopeId,IPAddress,HostName,ClientId,AddressState,LeaseExpiryTime,Description) are the ones the cmdlet returns. If you want to add a column, runGet-DhcpServerv4Lease -ScopeId <one scope> | Get-Memberfirst to see exactly what's available on your server version rather than guessing a name. - The housekeeping block only ever matches files named
DHCP-Leases_*.csvin that one folder, so it can't wander off and delete something else. Keep the$ReportRootfolder dedicated to these reports.
Run it once by hand:
powershell.exe -ExecutionPolicy Bypass -File C:\Scripts\Export-DhcpLeases.ps1
Open the CSV and confirm the scopes and lease counts match what you see in the DHCP console.
Optional: email the report
If you want the CSV mailed out, append this to the script and fill in your own relay and addresses. I'll be straight with you: Send-MailMessage is the built-in way and it works, but Microsoft has formally marked it obsolete and no longer maintains it — it's fine for an internal, unauthenticated relay on a trusted network, and if you need modern auth or TLS niceties you should reach for a maintained module instead (Microsoft's own docs on Send-MailMessage say as much and point you onward).
$mail = @{
From = 'dhcp-report@example.com'
To = 'netadmins@example.com'
Subject = "DHCP lease report $stamp"
Body = "DHCP lease report attached. $($leases.Count) leases."
Attachments= $csvPath
SmtpServer = 'smtp.example.com' # your internal relay
}
Send-MailMessage @mail
Replace example.com, the addresses, and smtp.example.com with your real values.
Schedule it
The mainstream path is a scheduled task that runs daily. You can build one in the Task Scheduler GUI, or create it from PowerShell with the built-in cmdlets — I'll use the cmdlets because they're repeatable. Run this once, in an elevated PowerShell session, to register the task:
$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
-Argument '-ExecutionPolicy Bypass -File C:\Scripts\Export-DhcpLeases.ps1'
$trigger = New-ScheduledTaskTrigger -Daily -At 6:00AM
# Run as SYSTEM. SYSTEM is a local account, so it needs read rights to
# DHCP - on the DHCP server itself SYSTEM can read the local service.
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' `
-LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName 'DHCP Lease Report' `
-Action $action -Trigger $trigger -Principal $principal `
-Description 'Daily IPv4 DHCP lease CSV export'
If you're emailing through a relay that only accepts a specific service account, register the task under that domain account instead of SYSTEM — use New-ScheduledTaskPrincipal -UserId 'EXAMPLE\svc-dhcpreport' and supply its password when prompted (or use -User/-Password on Register-ScheduledTask). Make sure that account is in DHCP Users or DHCP Administrators.
Verify it worked
Confirm the task exists and check its last result:
Get-ScheduledTask -TaskName 'DHCP Lease Report'
# Force a run now instead of waiting for 6 AM
Start-ScheduledTask -TaskName 'DHCP Lease Report'
# After it finishes, check the outcome (0x0 means success)
Get-ScheduledTaskInfo -TaskName 'DHCP Lease Report' |
Select-Object LastRunTime, LastTaskResult
Then confirm a fresh CSV appeared:
Get-ChildItem 'C:\Reports\DHCP' -Filter 'DHCP-Leases_*.csv' |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
Open that file and cross-check a scope's lease count against DHCP console → IPv4 → the scope → Address Leases. If the numbers agree, you're done.
Undo
Nothing here touched DHCP, so there's nothing to roll back on the server side. To remove the automation and its output:
Unregister-ScheduledTask -TaskName 'DHCP Lease Report' -Confirm:$false
Delete C:\Scripts\Export-DhcpLeases.ps1 and the C:\Reports\DHCP folder if you no longer want the reports. For the exact behaviour and parameters of any cmdlet above, the DhcpServer module and the ScheduledTasks module are both documented on Microsoft Learn — search the cmdlet name there before customising further.
Runs enterprise networks and security for a living, and writes Shore Up to turn two decades of hands-on Linux, Windows and mail-server work into guides you can actually use.
More about the author →Was this article helpful?
Tap a star — no sign-in needed.
Be the first to rate this article.
Related guides
Automate a Daily Failed-Logon (4625) Report with PowerShell
This guide builds a scheduled PowerShell job that reads Event ID 4625 (failed logon) from the Windows Security log for the last 24 hours and writes them to a dated HTML report. It is read-only — it queries the event log and creates a report file. It does not change auditing policy, delete events, or touch accounts.
Automate BitLocker Status Reporting Across a Fleet with PowerShell
This guide builds a read-only report: it collects the BitLocker encryption status of every fixed volume on a set of domain computers and writes it to a CSV. It does not enable, disable, or change BitLocker on anything. The only thing it creates on your side is the output file.
Monitor Free Disk Space and Email an Alert with PowerShell
This script reads the free space on the fixed local disks of the machine it runs on and emails you when any of them drops below a percentage you set. It is a lightweight stand-in for a monitoring platform — good for a handful of servers, not a replacement for one across a fleet.
Automate a Nightly Robocopy Mirror to a NAS with Verification
This sets up a nightly one-way mirror of a local folder to a NAS SMB share using robocopy /MIR , followed by a second pass that lists any remaining differences as a verification step, all logged to a timestamped file and driven by a Scheduled Task.




