Create a report on local DNS lookups using PowerShell

When troubleshooting a system, you sometimes need to know what DNS lookups are being done. This will give you a good insight into traffic from the systems to the local network or internet. You can do this with DNS auditing on your Windows server or in your local Pihole server, but that’s not always available 😉 In this blog post, I will show you an easy way to create a report on this without any extra tools.

What does the script do?

The script will run for the number of minutes you specify, during that period it will capture all unique DNS requests and create a report on them. By default, the script will output the DNS lookups to a grid view so that you can filter that when looking for specific items straight away. It also has the option, the -CSVPath parameter, to output it to a CSV file if needed. (The script will always show you the grid view option as the default output format). The -Minutes parameter is mandatory, with this you can specify the number of minutes the script should run before creating the report.

Running the script

After running the Get-DnsCacheReport.ps1 script, the Get-DnsCacheReport function is available. When running it, it looks like this: (In this example the script captures a minute of data and saves a report to c:\temp\dns.csv)

Get-DnsCacheReport -Minutes 1 -CSVPath c:\temp\dns.csv

When the minute is passed, it will show that the script is done:

The grid view pane will look like this:

And the CSV looks like this in Excel:

The script

Below is the script, it uses the Get-DNSClientCache cmdlet to retrieve the DNS cache from your client and will do this continuously during the countdown timer.

function Get-DnsCacheReport {
    param (
        [parameter(Mandatory = $true)][string]$Minutes,
        [parameter(Mandatory = $false)][string]$CSVPath
    )
    
    #check if a valid $CSVPath was provided if used
    if ($CSVPath) {
        if (New-Item -Path $CSVPath -ItemType File -Force:$true -ErrorAction SilentlyContinue) {
            Write-Host ("Path {0} is valid, continuing..." -f $CSVPath) -ForegroundColor Green
        }
        else {
            Write-Warning ("Path {0} is not valid, please check path or permissions. Aborting..." -f $CSVPath)
        }
    }

    #Start countdown, countdown to zero and restart programs again
    #Used countdown procedure from https://www.powershellgallery.com/packages/start-countdowntimer/1.0/Content/Start-CountdownTimer.psm1
    $t = New-TimeSpan -Minutes $Minutes
    $origpos = $host.UI.RawUI.CursorPosition
    $spinner = @('|', '/', '-', '\')
    $spinnerPos = 0
    $remain = $t
    $d = ( get-date) + $t
    [int]$TickLength = 1
    $remain = ($d - (get-date))
    while ($remain.TotalSeconds -gt 0) {
        Write-Host (" {0} " -f $spinner[$spinnerPos % 4]) -ForegroundColor Green -NoNewline
        write-host ("Gathering DNS Cache information, {0}D {1:d2}h {2:d2}m {3:d2}s remaining..." -f $remain.Days, $remain.Hours, $remain.Minutes, $remain.Seconds) -NoNewline -ForegroundColor Green
        $host.UI.RawUI.CursorPosition = $origpos
        $spinnerPos += 1
        Start-Sleep -seconds $TickLength
        
        #Get DNS Cache and add to $Total variable during the amount of minutes specified
        $dnscache = Get-DnsClientCache
        $total = foreach ($item in $dnscache) {
            #Switch table date is from https://www.darkoperator.com/blog/2020/1/14/getting-dns-client-cached-entries-with-cimwmi
            switch ($item.status) {
                0 { $status = 'Success' }
                9003 { $status = 'NotExist' }
                9501 { $status = 'NoRecords' }
                9701 { $status = 'NoRecords' }        
            }

            switch ($item.Type) {
                1 { $Type = 'A' }
                2 { $Type = 'NS' }
                5 { $Type = 'CNAME' }
                6 { $Type = 'SOA' }
                12 { $Type = 'PTR' } 
                15 { $Type = 'MX' }
                28 { $Type = 'AAAA' }
                33 { $Type = 'SRV' }
            }

            switch ($item.Section) {
                1 { $Section = 'Answer' }
                2 { $Section = 'Authority' }
                3 { $Section = 'Additional' }
            }

            [PSCustomObject]@{
                Entry      = $item.Entry
                RecordType = $Type
                Status     = $status
                Section    = $Section
                Target     = $item.Data            
            }
        }
        $remain = ($d - (get-date))
    }
    $host.UI.RawUI.CursorPosition = $origpos
    Write-Host (" * ")  -ForegroundColor Green -NoNewline
    write-host (" Finished gathering DNS Cache information, displaying results in a Out-Gridview now...") -ForegroundColor Green
    if ($CSVPath) {
        write-host ("Results are also saved as {0}" -f $CSVPath) -ForegroundColor Green
    }
    
    #Save results to $CSVPath if specified as parameter
    if ($CSVPath) {
        $total | Select-Object Entry, RecordType, Status, Section, Target -Unique | Sort-Object Entry | Export-Csv -Path $CSVPath -Encoding UTF8 -Delimiter ';' -NoTypeInformation -Force
    }
    
    #Return results in Out-Gridview
    return $total | Select-Object Entry, RecordType, Status, Section, Target -Unique | Sort-Object Entry | Out-GridView  
}

Download the script(s) from GitHub here

2 thoughts on “Create a report on local DNS lookups using PowerShell

Leave a Reply to Harm Veenstra Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.