Windows DHCP server

DHCP Server events are written to DHCP audit log files (if configured) and to Windows Event Log. This section provides details about configuring logging and collecting logs with NXLog.

DHCP audit logging

The Windows DHCP Server provides an audit logging feature that writes server activity to log files. NXLog can be configured to read and parse these logs.

The log files are named DhcpSrvLog-<DAY>.log for IPv4 and DhcpV6SrvLog-<DAY>.log for IPv6. For example, Thursday’s log files are DhcpSrvLog-Thu.log and DhcpV6SrvLog-Thu.log.

IPv4 log sample (many header lines omitted)
ID,Date,Time,Description,IP Address,Host Name,MAC Address,User Name, TransactionID, QResult,Probationtime, CorrelationID,Dhcid,VendorClass(Hex),VendorClass(ASCII),UserClass(Hex),UserClass(ASCII),RelayAgentInformation,DnsRegError.
00,05/11/18,03:14:55,Started,,,,,0,6,,,,,,,,,0
55,05/11/18,03:14:55,Authorized(servicing),,test.com,,,0,6,,,,,,,,,0
IPv6 log sample (many header lines omitted)
ID,Date,Time,Description,IPv6 Address,Host Name,Error Code, Duid Length, Duid Bytes(Hex),User Name,Dhcid,Subnet Prefix.
11010,05/11/18,03:14:55,DHCPV6 Started,,,,,,,,,,
1103,05/11/18,03:14:55,Authorized(servicing),,test.com,,,,,,,,

The DHCP audit log can be configured with PowerShell or the DHCP Management MMC snap-in.

The default audit log path, C:\Windows\System32\dhcp, is architecture-specific. To collect DHCP audit logs using a 32-bit NXLog agent on a 64-bit Windows system, it is recommended to change the log path to another directory that is not redirected to SysWOW64. For this reason, the following instructions use C:\dhcp. If the NXLog agent is running on the system’s native architecture, it is not necessary to change the log file location from the default.

Configure DHCP audit logs via PowerShell

  1. To view the current DHCP audit log configuration, run the following command (see Get-DhcpServerAuditLog on Microsoft Docs).

    > Get-DhcpServerAuditLog
    
    Path              : C:\Windows\system32\dhcp
    Enable            : True
    MaxMBFileSize     : 70
    DiskCheckInterval : 50
    MinMBDiskSpace    : 20
  2. To set the audit log configuration, run this command (see Set-DhcpServerAuditLog on Microsoft Docs).

    > Set-DhcpServerAuditLog -Enable $True -Path C:\dhcp
  3. The DHCP server must be restarted for the configuration changes to take effect.

    > Restart-Service DHCPServer

Configure audit logs via the DHCP Management Console

Follow these steps to configure DHCP audit logging. Any changes to the audit log settings apply to both IPv4 and IPv6 after the DHCP server is restarted.

  1. Run the DHCP MMC snap-in (dhcpmgmt.msc), expand the server for which to configure logging, and click on IPv4.

    DHCP Management MMC snap-in
  2. Right-click on IPv4 and click Properties. Note that the context menu is not fully populated until after the IPv4 menu has been expanded at least once.

    IPv4 Properties, General
  3. Make sure Enable DHCP audit logging is checked.

  4. Open the Advanced tab, change the Audit log file path, and click OK.

    IPv4 Properties, Advanced
  5. Restart the DHCP server by right-clicking the server and clicking All Tasks > Restart.

Collecting DHCP server audit logs

The DHCP audit logs are stored in CSV format with a large free-form header containing a list of event ID descriptions and other details.

Example 1. Collecting and parsing DHCP audit logs

This configuration uses a batch/PowerShell polyglot script with the include_stdout directive to fetch the DHCP audit log location. The im_file module reads the audit logs and the xm_csv module parses the lines into fields. Any line that does not match the /^\d+,/ regular expression is discarded with the drop() procedure (all the header lines are dropped). The event ID and QResult codes are resolved automatically, with corresponding $Message and $QMessage fields added where applicable.

If DHCP audit logging is disabled, the script will print an error and NXLog will abort during the configuration check.
nxlog.conf
<Extension dhcp_csv_parser>
    Module      xm_csv
    Fields      ID, Date, Time, Description, IPAddress, Hostname, MACAddress, \
                UserName, TransactionID, QResult, ProbationTime, CorrelationID, \
                DHCID, VendorClassHex, VendorClassASCII, UserClassHex, \
                UserClassASCII, RelayAgentInformation, DnsRegError
</Extension>

<Extension dhcpv6_csv_parser>
    Module      xm_csv
    Fields      ID, Date, Time, Description, IPv6Address, Hostname, ErrorCode, \
                DuidLength, DuidBytesHex, UserName, Dhcid, SubnetPrefix
</Extension>

<Input dhcp_server_audit>
    Module          im_file
    include_stdout  %CONFDIR%\dhcp_server_audit_include.cmd
    <Exec>
        # Only process lines that begin with an event ID
        if $raw_event =~ /^\d+,/
        {
            $FileName = file_name();
            if $FileName =~ /DhcpSrvLog-/
            {
                dhcp_csv_parser->parse_csv();
                $QResult = integer($QResult);
                if $QResult == 0 $QMessage = "NoQuarantine";
                else if $QResult == 1 $QMessage = "Quarantine";
                else if $QResult == 2 $QMessage = "Drop Packet";
                else if $QResult == 3 $QMessage = "Probation";
                else if $QResult == 6 $QMessage = "No Quarantine Information";
            }
            else
            {
                dhcpv6_csv_parser->parse_csv();
            }
            $EventTime = strptime($Date + ' ' + $Time, '%m/%d/%y %H:%M:%S');
            $ID = integer($ID);
            # DHCP Event IDs
            if $ID == 0 $Message = "The log was started.";
            else if $ID == 1 $Message = "The log was stopped.";
            else if $ID == 2
                $Message = "The log was temporarily paused due to low disk space.";
            else if $ID == 10 $Message = "A new IP address was leased to a client.";
            else if $ID == 11 $Message = "A lease was renewed by a client.";
            else if $ID == 12 $Message = "A lease was released by a client.";
            else if $ID == 13
                $Message = "An IP address was found to be in use on the network.";
            else if $ID == 14
                $Message = "A lease request could not be satisfied because the " +
                           "scope's address pool was exhausted.";
            else if $ID == 15 $Message = "A lease was denied.";
            else if $ID == 16 $Message = "A lease was deleted.";
            else if $ID == 17
                $Message = "A lease was expired and DNS records for an expired " +
                           "leases have not been deleted.";
            else if $ID == 18
                $Message = "A lease was expired and DNS records were deleted.";
            else if $ID == 20
                $Message = "A BOOTP address was leased to a client.";
            else if $ID == 21
                $Message = "A dynamic BOOTP address was leased to a client.";
            else if $ID == 22
                $Message = "A BOOTP request could not be satisfied because the " +
                           "scope's address pool for BOOTP was exhausted.";
            else if $ID == 23
                $Message = "A BOOTP IP address was deleted after checking to see " +
                           "it was not in use.";
            else if $ID == 24
                $Message = "IP address cleanup operation has began.";
            else if $ID == 25
                $Message = "IP address cleanup statistics.";
            else if $ID == 30
                $Message = "DNS update request to the named DNS server.";
            else if $ID == 31 $Message = "DNS update failed.";
            else if $ID == 32 $Message = "DNS update successful.";
            else if $ID == 33
                $Message = "Packet dropped due to NAP policy.";
            else if $ID == 34
                $Message = "DNS update request failed as the DNS update request " +
                           "queue limit exceeded.";
            else if $ID == 35 $Message = "DNS update request failed.";
            else if $ID == 36
                $Message = "Packet dropped because the server is in failover " +
                           "standby role or the hash of the client ID does not " +
                           "match.";
            else if ($ID >= 50 and $ID < 1000)
                $Message = "Codes above 50 are used for Rogue Server Detection " +
                           "information.";
            # DHCPv6 Event IDs
            else if $ID == 11000 $Message = "DHCPv6 Solicit.";
            else if $ID == 11001 $Message = "DHCPv6 Advertise.";
            else if $ID == 11002 $Message = "DHCPv6 Request.";
            else if $ID == 11003 $Message = "DHCPv6 Confirm.";
            else if $ID == 11004 $Message = "DHCPv6 Renew.";
            else if $ID == 11005 $Message = "DHCPv6 Rebind.";
            else if $ID == 11006 $Message = "DHCPv6 Decline.";
            else if $ID == 11007 $Message = "DHCPv6 Release.";
            else if $ID == 11008 $Message = "DHCPv6 Information Request.";
            else if $ID == 11009 $Message = "DHCPv6 Scope Full.";
            else if $ID == 11010 $Message = "DHCPv6 Started.";
            else if $ID == 11011 $Message = "DHCPv6 Stopped.";
            else if $ID == 11012 $Message = "DHCPv6 Audit log paused.";
            else if $ID == 11013 $Message = "DHCPv6 Log File.";
            else if $ID == 11014 $Message = "DHCPv6 Bad Address.";
            else if $ID == 11015 $Message = "DHCPv6 Address is already in use.";
            else if $ID == 11016 $Message = "DHCPv6 Client deleted.";
            else if $ID == 11017 $Message = "DHCPv6 DNS record not deleted.";
            else if $ID == 11018 $Message = "DHCPv6 Expired.";
            else if $ID == 11019
                $Message = "DHCPv6 Leases Expired and Leases Deleted.";
            else if $ID == 11020 $Message = "DHCPv6 Database cleanup begin.";
            else if $ID == 11021 $Message = "DHCPv6 Database cleanup end.";
            else if $ID == 11022 $Message = "DNS IPv6 Update Request.";
            else if $ID == 11023 $Message = "DNS IPv6 Update Failed.";
            else if $ID == 11024 $Message = "DNS IPv6 Update Successful.";
            else if $ID == 11028
                $Message = "DNS IPv6 update request failed as the DNS update " +
                           "request queue limit exceeded.";
            else if $ID == 11029 $Message = "DNS IPv6 update request failed.";
            else if $ID == 11030
                $Message = "DHCPv6 stateless client records purged.";
            else if $ID == 11031
                $Message = "DHCPv6 stateless client record is purged as the " +
                           "purge interval has expired for this client record.";
            else if $ID == 11032
                $Message = "DHCPV6 Information Request from IPV6 Stateless Client.";
            else $Message = "No message specified for this Event ID.";
        }
        # Discard header lines (which do not begin with an event ID)
        else drop();
    </Exec>
</Input>
dhcp_server_audit_include.cmd
@( Set "_= (
REM " ) <#
)
@Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
powershell.exe -ExecutionPolicy Bypass -NoProfile ^
-Command "iex ((gc '%~f0') -join [char]10)"
EndLocal & Exit /B %ErrorLevel%
#>
$AuditLog = Get-DhcpServerAuditLog
if ($AuditLog.Enable) {
    Write-Output "File '$($AuditLog.Path)\Dhcp*SrvLog-*.log'"
}
else {
    [Console]::Error.WriteLine(@"
DHCP audit logging is disabled. To enable, run in PowerShell:
> Set-DhcpServerAuditLog -Enable $True
"@)
    exit 1
}

DHCP server logs in Windows Event Log

Events are also written to three logs in the Windows Event Log. To make sure the required logs are enabled, open Event Viewer (eventvwr) and check the logs under Applications and Services Logs > Microsoft > Windows > DHCP-Server. To enable a log, right-click on it and click Enable Log.

Enabling DHCP server logs

Alternatively, the following PowerShell script will check all three DHCP logs, enabling if necessary.

$LogNames = @("DhcpAdminEvents",
              "Microsoft-Windows-Dhcp-Server/FilterNotifications",
              "Microsoft-Windows-Dhcp-Server/Operational")
ForEach ($LogName in $LogNames) {
    $EventLog = Get-WinEvent -ListLog $LogName
    if ($EventLog.IsEnabled) {
        Write-Host "Already enabled: $LogName"
    }
    else {
        Write-Host "Enabling: $LogName"
        $EventLog.IsEnabled = $true
        $EventLog.SaveChanges()
    }
}
Example 2. Collecting DHCP server logs from Windows Event Log

This configuration uses the im_msvistalog module to collect DHCP Server event logs from the DhcpAdminEvents, FilterNotifications, and Operational logs.

nxlog.conf
<Input dhcp_server_eventlog>
    Module  im_msvistalog
    <QueryXML>
        <QueryList>
            <Query Id="0">
                <Select Path="DhcpAdminEvents">*</Select>
                <Select Path="Microsoft-Windows-Dhcp-Server/FilterNotifications">
                        *</Select>
                <Select Path="Microsoft-Windows-Dhcp-Server/Operational">*</Select>
            </Query>
        </QueryList>
    </QueryXML>
</Input>
Disclaimer

While we endeavor to keep the information in this topic up to date and correct, NXLog makes no representations or warranties of any kind, express or implied about the completeness, accuracy, reliability, suitability, or availability of the content represented here.

The accurateness of the content was tested and proved to be working in our lab environment at the time of the last revision with the following software versions:

Windows Server 2022
Windows Server 2019
Windows Server 2016
NXLog version 5.4.7313

Last revision: 26 January 2022