PowerShell How-To

Using PowerShell To Parse and Understand Windows Server DHCP Logs

Have you ever scrolled through the Windows Server DHCP logs in the Notepad app while trying to troubleshoot something? Then you know that it's a tedious task.

There are many alternatives to Notepad such as importing to Excel, but that's also time-consuming -- even more so if you have several DHCP servers in a failover cluster.

In this column, we'll go through how to collect, parse and understand the Windows Server DHCP logs with the help of PowerShell.

Requirements
There are a few things that you'll need before following along in this post:

  • A Windows DHCP server (I based this post on Windows Server 2019 but it should work the same for at least 2012 R2 and up).
  • Local administrator rights on the DHCP server(s).
  • WSMan (PowerShell remoting) and its required ports opened on the DHCP server(s).
  • PowerShell 5.1 (it may work with other versions but it's not tested).

Enabling Your DHCP Audit Logs
First, we need to make sure that the DHCP audit logs are enabled. This is easily done through PowerShell and it will just take a minute. Log on to the DHCP server, open PowerShell as an Administrator, then enter the following command:

  PS51> Get-DhcpServerAuditLog

If enabled equals True as in the picture below, then you're good to go.

If it isn't enabled, then you need to enter the following commands that will enable it and restart the DHCP service:

  Set-DhcpServerAuditLog -Enable $True -MaxMBFileSize 70
  Restart-Service DhcpServer

The audit log is now enabled.

Repeat this for all servers in your DHCP cluster (if any).

Finding the Logs
Before parsing the DHCP logs, it's a good idea to learn where to find them.

The DHCP audit logs are usually located in C:32* and follow the naming context DhcpSrvLog-.log* for IPv4 logs and DhcpV6SrvLog-.log  for the first three letters of the day written in English. We can easily locate them using PowerShell:

PS51> Get-ChildItem C:\Windows\system32\dhcp\Dhcp*SrvLog-*.log | Select -ExpandProperty Name

DhcpSrvLog-Fri.log
DhcpSrvLog-Mon.log
DhcpSrvLog-Sat.log
DhcpSrvLog-Sun.log
DhcpSrvLog-Thu.log
DhcpSrvLog-Tue.log
DhcpSrvLog-Wed.log
DhcpV6SrvLog-Fri.log
DhcpV6SrvLog-Mon.log
DhcpV6SrvLog-Sat.log
DhcpV6SrvLog-Sun.log
DhcpV6SrvLog-Thu.log
DhcpV6SrvLog-Tue.log
DhcpV6SrvLog-Wed.log

If you can't find your audit logs here, then run the PowerShell command Get-DhcpServerAuditLog to see in what directory they are saved under the property Path. Also, double-check that you've enabled the audit logs and restarted the DhcpServer service as we described previously.

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. If you would like to learn more about the different events codes in the CSV columns, you can read Microsoft's documentation here.

Parsing the Audit Log with PowerShell
Using PowerShell is one of the best ways to parse a DHCP audit log. It can also easily be executed on several DHCP servers at once so you don't have to run it manually on each one.

The script below will use PowerShell remoting to connect to all of your DHCP servers at once to collect the logs and output them as objects instead of CSV:

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

}

If we want to fetch audit logs from one or several DHCP servers, we just have to run the following as a user with remoting permissions to the server(s):

# To collect logs from one server
Get-RemoteDhcpAuditLogs -ComputerName srvDhcp01 -Day Tue -Protocol IPv4

# To collect logs from several servers
Get-RemoteDhcpAuditLogs -ComputerName srvDhcp01,srvDhcp02 -Day Tue -Protocol IPv4

This returns a regular PSObject collection that we can filter like this:

Get-RemoteDhcpAuditLogs -ComputerName srvDhcp01 -Day Tue -Protocol IPv4 | Where-Object {$_.'IP Address' -eq "10.10.45.10"}

You can filter on all the properties of the object, making troubleshooting a lot easier (for example, mac, host name and so on).

Summary
Learning how to easily interpret and search the DHCP audit logs is half the battle when it comes to troubleshooting DHCP. And using PowerShell as a tool for that makes it so much quicker.

Creating a PowerShell function for collecting logs it makes it so much easier for us, especially considering that we don't have to RDP to the DHCP server to run it. Also, running the log collection as a job and not as a regular Invoke-Command makes it so much faster.

About the Author

Adam Bertram is a 20-year veteran of IT. He's an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam also founded the popular TechSnips e-learning platform. He mainly focuses on DevOps, system management and automation technologies, as well as various cloud platforms mostly in the Microsoft space. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion. Catch up on Adam's articles at adamtheautomator.com, connect on LinkedIn or follow him on Twitter at @adbertram or the TechSnips Twitter account @techsnips_io.


comments powered by Disqus
Most   Popular