Introduction to DHCP Audit Logging on Windows Server 2019
DHCP Audit Logging records every IP address assignment, renewal, release, and denial made by the DHCP server. This log is invaluable for network troubleshooting (tracking which machine had a given IP at a specific time), security investigation (identifying rogue devices or tracking when an infected machine joined the network), and compliance (demonstrating IP allocation history for audits). Windows Server 2019 enables DHCP audit logging by default, but the default configuration — rotating daily log files with a 70MB cap — may not suit enterprise requirements. This guide covers the full configuration, maintenance, and analysis of DHCP audit logs.
How DHCP Audit Logging Works
The DHCP Server role writes plain-text comma-delimited log files to C:WindowsSystem32DHCP by default. Each file is named by day of week: DhcpSrvLog-Mon.log, DhcpSrvLog-Tue.log, and so on. When the day changes, the existing file for that day is overwritten from scratch. This means by default you retain 7 days of history — one week of log data. Each line in the log follows a defined CSV format with Event ID, Date, Time, Description, IP Address, hostname, and MAC address fields.
# Verify audit logging is enabled (should be True by default)
Get-DhcpServerAuditLog | Format-List
# Output includes:
# Enable : True
# Path : C:WindowsSystem32DHCP
# MaxMBFileSize : 70
# DiskCheckInterval : 50
# MinMBDiskSpace : 20
Verify and Enable Audit Logging
# Enable DHCP audit logging if it is disabled
Set-DhcpServerAuditLog -Enable $true
# Confirm
Get-DhcpServerAuditLog | Select-Object Enable, Path, MaxMBFileSize
Change the Log File Location and Size
The default path inside System32 is not ideal for log management. Move the logs to a dedicated volume with adequate space, and increase the size cap to retain more data per day:
# Create a dedicated log directory
New-Item -ItemType Directory -Path "D:DHCPLogs" -Force
# Update DHCP audit log settings
Set-DhcpServerAuditLog `
-Enable $true `
-Path "D:DHCPLogs" `
-MaxMBFileSize 500 `
-DiskCheckInterval 50 `
-MinMBDiskSpace 100
# Restart DHCP Server to apply new path
Restart-Service -Name DHCPServer
# Verify logs are being written to new location
Get-ChildItem -Path "D:DHCPLogs" | Select-Object Name, Length, LastWriteTime
The DiskCheckInterval (default 50) specifies how many log entries are written before the server checks available disk space. The MinMBDiskSpace (default 20MB) is the minimum free disk space required — if disk space falls below this threshold, DHCP stops writing audit logs to prevent filling the disk, and logs Event ID 1023.
Understanding DHCP Audit Log Event IDs
Each log entry begins with a numeric Event ID. The most important IDs are:
# DHCP Audit Log Event IDs Reference:
# 00 - Log start
# 01 - Log end
# 02 - Log pause (disk full)
# 10 - New IP address lease granted
# 11 - Lease renewed
# 12 - Lease released (client issued DHCPRELEASE)
# 13 - IP address found in use (conflict detection)
# 14 - Lease expired and deleted
# 15 - Lease deleted manually
# 16 - DNS record deleted
# 17 - Expired and DNS records deleted
# 20 - Migration of lease from old DHCP database
# 21 - Lease recovered (database failover)
# 24 - IP address state deleted (from database cleanup)
# 25 - Lease expired (but not yet deleted)
# 31 - DNS Update request
# 32 - DNS Update failed
# 33 - DNS Update successful
# 50+ - Rogue server authorisation events
Parse DHCP Audit Logs with PowerShell
The daily log files are plain CSV but include a header block. Parse them to extract useful information:
# Read today's DHCP log
$dayOfWeek = (Get-Date).DayOfWeek.ToString().Substring(0,3)
$logFile = "D:DHCPLogsDhcpSrvLog-$dayOfWeek.log"
# The first several lines are headers; skip until we reach the data
$lines = Get-Content $logFile
$dataLines = $lines | Where-Object { $_ -match "^[0-9]+" }
# Parse into objects
$leases = $dataLines | ForEach-Object {
$fields = $_ -split ","
[PSCustomObject]@{
EventID = $fields[0].Trim()
Date = $fields[1].Trim()
Time = $fields[2].Trim()
Description= $fields[3].Trim()
IPAddress = $fields[4].Trim()
Hostname = $fields[5].Trim()
MACAddress = $fields[6].Trim()
}
}
# Show all new leases (Event 10) from today
$leases | Where-Object EventID -eq "10" |
Select-Object Date, Time, IPAddress, Hostname, MACAddress | Format-Table
# Find all times a specific IP was assigned
$leases | Where-Object IPAddress -eq "192.168.100.55" | Format-Table
# Find which MAC address had a specific IP
$leases | Where-Object { $_.IPAddress -eq "192.168.100.100" -and $_.EventID -eq "10" } |
Select-Object Date, Time, MACAddress, Hostname | Format-Table
# Count lease grants per hour (activity heatmap)
$leases | Where-Object EventID -eq "10" |
Group-Object { ($_.Time -split ":")[0] } |
Sort-Object Name | Select-Object Name, Count | Format-Table
Archive and Retain Historical Logs
The 7-day rotating log retention is insufficient for compliance or post-incident investigation. Create a scheduled task to archive logs daily before they are overwritten:
# Create archive directory structure
$archivePath = "D:DHCPLogsArchive"
New-Item -ItemType Directory -Path $archivePath -Force
# Archive script content
$archiveScript = @'
$date = Get-Date -Format "yyyy-MM-dd"
$dayOfWeek = (Get-Date).AddDays(-1).DayOfWeek.ToString().Substring(0,3)
$source = "D:DHCPLogsDhcpSrvLog-$dayOfWeek.log"
$dest = "D:DHCPLogsArchiveDhcpSrvLog-$date.log"
if (Test-Path $source) {
Copy-Item -Path $source -Destination $dest
Write-EventLog -LogName Application -Source "DHCPArchive" -EventId 9900 -Message "Archived DHCP log to $dest"
}
# Clean up archives older than 90 days
Get-ChildItem -Path "D:DHCPLogsArchive" -Filter "*.log" |
Where-Object LastWriteTime -lt (Get-Date).AddDays(-90) |
Remove-Item -Force
'@
$archiveScript | Set-Content -Path "C:ScriptsArchive-DHCPLogs.ps1"
# Register as a scheduled task running daily at 11:55 PM
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -File C:ScriptsArchive-DHCPLogs.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "23:55"
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 5)
Register-ScheduledTask -TaskName "Archive-DHCPLogs" `
-Action $action -Trigger $trigger `
-RunLevel Highest -Settings $settings -Force
Search Archived Logs for Incident Investigation
# Search all archived logs for a specific MAC address
Get-ChildItem -Path "D:DHCPLogsArchive" -Filter "*.log" | ForEach-Object {
$matches = Get-Content $_.FullName |
Where-Object { $_ -match "00-50-56-AB-CD-EF" }
if ($matches) {
Write-Host "Found in $($_.Name):"
$matches | ForEach-Object { Write-Host " $_" }
}
}
# Find IP history for a specific hostname
Get-ChildItem -Path "D:DHCPLogsArchive" -Filter "*.log" | ForEach-Object {
Get-Content $_.FullName |
Where-Object { $_ -match "WORKSTATION01" -and $_ -match "^10," }
} | ForEach-Object { Write-Host $_ }
Forward DHCP Events to Windows Event Log
For SIEM integration, DHCP events can also be captured from the Windows Event Log rather than text log parsing:
# DHCP Server service events appear in System log
Get-WinEvent -LogName System |
Where-Object { $_.ProviderName -match "DhcpServer" } |
Select-Object TimeCreated, Id, Message | Format-List
# Relevant System Event IDs for DHCP Server:
# 1000 - DHCP Server started
# 1001 - DHCP Server stopped
# 1022 - No audit log file (cannot create)
# 1023 - Low disk space, audit log paused
# 1055 - Rogue DHCP server detected
Summary
DHCP Audit Logging on Windows Server 2019 is a straightforward but powerful feature that captures every IP address transaction. The key steps for a production-ready configuration are: move logs to a dedicated volume, increase the per-file size cap, implement daily archiving to extend retention beyond 7 days, and build PowerShell parsing scripts for rapid investigation. Combined with SIEM forwarding of Windows Event Log DHCP events, this gives you complete visibility into IP address allocation history across your environment.