Published on

DHCP

Authors
  • Name
    Jackson Chen

Troubleshooting on DHCP server

Verify listening ports

Verify that only the DHCP server is listening on UDP port 67 and 68. No other process or other services (such as WDS or PXE) should occupy these ports.

# Run command
    netstat -anb
Verify Event log

Check the System and DHCP Server service event logs for reported issues that are related to the observed problem.

Applications and Services Logs > Microsoft > Windows > DHCP-Server

DHCP Audit Logs

Enabling Your DHCP Audit Logs

Check DHCP audit logs are enabled

# PowerShell
Get-DhcpServerAuditLog

Result
a. Path     c:\windows\system32\dhcp
b. Enable   True

# If not enable, then enble it
Set-DhcpServerAuditLog -Enable $True -MaxMBFileSize 70
Restart-Service DhcpServer

Audit Log location

The DHCP audit logs are follow the naming context DhcpSrvLog-.log* for IPv4 logs and DhcpV6SrvLog-.log for the first three letters of the day written in English.

# Get dhcp audit logs
Get-ChildItem C:\Windows\system32\dhcp\Dhcp*SrvLog-*.log | Select -ExpandProperty Name
Understanding the Contents

Interpreting the logs is also fundamental while troubleshooting. The DHCP audit log files consists of two parts:

Roughly 32 lines mainly describing what the different event codes (ID and QResult) mean in the CSV. A CSV with a header. Most of the columns are pretty well-described by their headers. But the ID column can sometimes be quite cryptic, so I summarized a list of all the IPv4 ID descriptions both from the log files and Microsoft's official documentation below:

0: The log was started.
1: The log was stopped.
2: The log was temporarily paused due to low disk space.
10: A new IP address was leased to a client.
11: A lease was renewed by a client.
12: A lease was released by a client.
13: An IP address was found to be in use on the network.
14: A lease request could not be satisfied because the scope's address pool was exhausted.
15: A lease was denied.
16: A lease was deleted.
17: A lease was expired and DNS records for an expired leases have not been deleted.
18: A lease was expired and DNS records were deleted.
20: A BOOTP address was leased to a client.
21: A dynamic BOOTP address was leased to a client.
22: A BOOTP request could not be satisfied because the scope's address pool for BOOTP was exhausted.
23: A BOOTP IP address was deleted after checking to see it was not in use.
24: IP address cleanup operation has began.
25: IP address cleanup statistics.
30: DNS update request to the name DNS server.
31: DNS update failed.
32: DNS update successful.
33: Packet dropped due to NAP policy.
34: DNS update request failed as the DNS update request queue limit exceeded.
35: DNS update request failed.
36: Packet dropped because the serve is in failover standby role or the hash of the client ID does not match.
50: Unreachable domain
51: Authorization succeeded
52: Upgraded to a Windows Server 2003 operating system
53: Cached Authorization
54: Authorization failed
55: Authorization (servicing)
56: Authorization failure, stopped servicing
57: Server found in domain
58: Server could not find domain
59: Network failure
60: No DC is DS Enabled
61: Server found that belongs to DS domain
62: Another server found
63: Restarting rogue detection
64: No DHCP enabled interfaces

There's also the QResult column that specifies if a client has been blocked from receiving an IP address with the following description to its IDs:

0: NoQuarantine
1: Quarantine
2: Drop Packet
3: Probation
6: No Quarantine

Additional data is almost always supplied in the Description column.

Parsing the auditing logs

Function Get-RemoteDhcpAuditLog {
    Param(
        [parameter(Mandatory)]
        [string[]]$ComputerName,    
        [parameter(Mandatory)]
        [ValidateSet('Mon','Tue','Wed','Thu','Fri','Sat','Sun','*')]
        [string]$Day = '*',
        [parameter(Mandatory)]
        [ValidateSet('IPv4','IPv6')]
        [string]$Protocol = 'IPv4',
        [string]$LogPath = "C:\Windows\System32\dhcp"
    )

    $Parameters = @{
        Day = $Day
        LogPath = $LogPath
    }

    Switch($Protocol){
        IPv6 {$Parameters["Protocol"] = "v6"}
        IPv4 {$Parameters["Protocol"] = ""}
    }

    $Job = Invoke-Command -AsJob -ArgumentList $Parameters -ComputerName $ComputerName -ScriptBlock {
        $Parameters = $Args[0]
    
        $LogFiles = Get-ChildItem -Path "$($Parameters.LogPath)\Dhcp$($Parameters.Protocol)SrvLog-$($Parameters.Day).log"
        Foreach($LogFile in $LogFiles){
            # Read the log file
            $LogContent = Cat $LogFile

            # Determine start row of CSV
            $StartRow = 0
            $LogContent | Foreach {
                if($_ -match "^ID,Date"){
                    Break
                }
                Else{
                    $StartRow++
                }
            }

            # Create expressions to use with Select-Object
            $DateTimeExpression = @{
                Name="Date"
                Expression={
                    $_.Date -match "(?\d\d)/(?\d\d)/(?\d\d)" | Out-Null
                    Get-Date "20$($Matches.year)-$($Matches.month)-$($Matches.day) $($_.Time)"
                }
            }
            # Output as CSV from row $StartRow
            $LogContent | Select -Skip $StartRow | ConvertFrom-Csv -Delimiter "," | Select $DateTimeExpression,* -ExcludeProperty Date,Time
        }    
    }

    $Job | Wait-Job
    $Job | Receive-Job
}

# Troubleshooting by filtering ip, mac, hostname
Get-RemoteDhcpAuditLog -ComputerName srvDhcp01 -Day Tue -Protocol IPv4 | Where-Object {$_.'IP Address' -eq "10.10.45.10"}