This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

About this documentation

This is the official documentation site for DNSServer.DebugLogParser, a PowerShell module that transforms Windows DNS Server debug log files into structured, analyzable CSV data.

About the module

DNSServer.DebugLogParser was born from a real-world need: Windows DNS Server debug logs are human-readable text, but not suitable for analytics or reporting. This module bridges that gap by converting raw log files into structured CSV format that integrates with common tools like Excel, Power BI, SQL databases, and SIEM systems.

Key design principles:

  • Performance first — optimized for 100MB+ files using streaming I/O and string operations
  • Cross-edition compatibility — supports PowerShell Desktop (5.1+) and Core (7.x)
  • Production-ready — includes header validation, error handling, and optional compression
  • Pipeline-friendly — integrates naturally with PowerShell’s pipeline architecture

What is here

SectionRead it when
OverviewYou want to know what the module does and whether it fits your problem
Output FormatsYou need to know what the CSV columns mean before designing a pipeline
Parameters and OptionsYou are deciding which switches your conversion needs
PerformanceYour logs are large or your conversion is slower than expected
IntegrationYou are loading the results into Excel, Power BI, SQL, a SIEM, or Python
Operational Best PracticesYou are about to run this unattended in production
Usage ExamplesYou want a worked end-to-end scenario to adapt
TroubleshootingSomething does not behave as expected
Command ReferenceYou need the authoritative parameter list

New to the module? Start with the Overview.

Resources

Contributing

Contributions are welcome. If you find issues, errors, or have suggestions for improvements, please open an issue or pull request on the GitHub repository.

1 - Overview

What DNSServer.DebugLogParser does, what a Windows DNS debug log looks like, and when converting it to CSV is worth the effort.

Windows DNS Server can write a debug log. It is a plain text file, it is meant to be read by a human, and it grows by hundreds of megabytes a day on a busy domain controller. That combination makes it nearly useless the moment you want to answer a question like “which client asked for this domain 40.000 times last night?”

DNSServer.DebugLogParser turns that text file into a CSV table. One log line becomes one row with named columns, so you can open it in Excel, load it into Power BI, bulk-insert it into SQL Server, or ship it to your SIEM.

The module contains a single command:

Convert-DNSDebugLogFile -InputFile "C:\Windows\System32\dns\dns.log"

That is the whole entry point. Everything else on this site is about doing it at scale, on a schedule, and across several servers.

What a DNS debug log looks like

A raw entry is a single line with positional fields, some of them in brackets:

2026-01-20 23:00:16 0FE0 PACKET 000002C53117D990 UDP Rcv 10.0.0.2 c049 Q [0001 D NOERROR] A (3)odc(9)officeapps(4)live(3)com(0)

After conversion, the same event is a CSV row you can filter and sort:

DateTime;ThreadId;Context;PacketId;Protocol;Direction;ClientIP;Xid;Type;Opcode;FlagsHex;FlagsChar;ResponseCode;QuestionType;QuestionName;Information;Details;ComputerName
2026-01-20 23:00:16;0FE0;Packet;000002C53117D990;UDP;Rcv;10.0.0.2;c049;Query;Standard;0001;RecursionDesired;NOERROR;A;"odc.officeapps.live.com";"";"";dc01

Note two things that the raw format makes hard and the parser handles for you:

  • The queried name is stored in DNS wire notation, (3)odc(9)officeapps(4)live(3)com(0), and becomes a normal FQDN.
  • A single event is not always a single line. PACKET detail blocks and event messages continue on indented follow-up lines. The parser keeps those attached to the record they belong to instead of dropping them or creating orphan rows.

Every entry carries up to 16 native fields — timestamp, protocol, direction, client IP, query type, queried name, response code, flags, and more. The full column list is described in Output Formats.

Why bother converting

Troubleshooting

  • Find out why a name does not resolve, and whether the query even reached the server
  • Identify misconfigured clients or applications that hammer the server
  • Trace where a problematic query actually comes from
  • Verify zone transfers and general DNS behaviour

Performance and capacity

  • Rank clients by query volume and find the noisy ones
  • See which record types dominate your traffic
  • Spot configuration mistakes that cause avoidable lookups
  • Track server load over time instead of guessing

Security analysis

  • Detect DNS tunneling and data exfiltration (typically visible as excessive TXT traffic — see the SQL Server analysis example)
  • Find lookups against malware and command-and-control domains
  • Recognize query patterns of a compromised host
  • Watch for DNS amplification abuse
  • Reconstruct what happened during an incident

Compliance and auditing

  • Satisfy logging and retention obligations
  • Keep an audit trail of network activity
  • Produce reports for management or auditors

How the module works

Convert-DNSDebugLogFile reads the log as a stream and writes the CSV as a stream. The file is never loaded into memory as a whole, so a 100 MB log costs roughly the same amount of RAM as a 10 MB one. Details are in Performance.

What it gives you:

CapabilityDetail
Consistent CSV layout18 columns, same order every time, regardless of which contexts appear in the log
Multi-line recordsPACKET detail blocks and event text stay attached to their record
DNS Server versions2012 R2 through 2025 log formats
PowerShell editionsWindows PowerShell 5.1+ and PowerShell 7.x
File sizeTested with 100 MB+ logs; single-pass streaming
Header validationRejects files that are not DNS debug logs (can be switched off)
StatisticsOptional daily rollups, per context and per client/protocol/type
Pipeline supportGet-ChildItem *.log | Convert-DNSDebugLogFile
CompressionOptional ZIP output, typically 90 %+ smaller
Source cleanupOptional deletion of the log after a successful run
International logsParses and writes dates per culture, so a de-DE log can be read on an en-US workstation
Network pathsReads sources from SMB/UNC paths
Locked filesReads logs that DNS Server (or anything else) currently has open

Active log vs. rotated log

The practical pattern is to enable log rollover on the DNS server and let the scheduled conversion skip the newest file:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" |
    Sort-Object LastWriteTime -Descending |
    Select-Object -Skip 1 |
    Convert-DNSDebugLogFile -ComputerName $env:COMPUTERNAME

A complete Group Policy based implementation of this is documented in the GPO-driven collection example.

Where to go next

Licensing and support

MIT License. Community support runs through GitHub Issues; bug reports and feature requests are welcome.

2 - Output Formats

The columns of the CSV data file, the two optional statistics files, and real sample outputs you can open before you run anything.

Convert-DNSDebugLogFile produces up to three files per input log:

FileContainsCreated when
<name>.csvOne row per parsed log entry-OutputType CSV or Both
<name>_Statistic.csvDaily record count per context-OutputType Statistic or Both
<name>_PacketStatistic.csvDaily query count per client, protocol, direction and record type-OutputType Statistic or Both

Both is the default. Output lands next to the input file unless you set -OutputFile.

The sample files linked on this page are real conversion results, not mock-ups. Download one and open it in Excel before you commit to a pipeline design.

The CSV data file

Sample output:

LocaleDetails columnFiles
en-USnot populatedWithComputerName, NoComputerName
de-DEnot populatedWithComputerName, NoComputerName
de-DEpopulatedWithComputerName, NoComputerName

Two rows from a real conversion — a DNS query and a server-internal note:

DateTime;ThreadId;Context;PacketId;Protocol;Direction;ClientIP;Xid;Type;Opcode;FlagsHex;FlagsChar;ResponseCode;QuestionType;QuestionName;Information;Details;ComputerName
2026-01-20 23:00:16;0FE0;Packet;000002C53117D990;UDP;Rcv;10.0.0.2;c049;Query;Standard;0001;RecursionDesired;NOERROR;A;"odc.officeapps.live.com";"";"";dc01
2026-01-20 23:00:16;DF0;Note;;;;;;;;;;;;"";"got GQCS failure on a dead socket context status=995, socket=904";"";dc01

Columns

Always 18 columns, always in this order:

#ColumnMeaningTypical use
1DateTimeTimestamp of the entryTime filtering, joining with other logs
2ThreadIdDNS server worker threadRarely needed; useful when correlating server-internal issues
3ContextKind of entry: Packet, Event, Note, DSPoll, Init, Lookup, Recurse, Remote, TombstoneFirst filter you will apply — Packet is the actual DNS traffic
4PacketIdInternal packet identifierPairing a query with its response
5ProtocolUDP or TCPTCP spikes can indicate large responses or zone transfers
6DirectionRcv (query came in) or Snd (server answered)Split request volume from response volume
7ClientIPAddress of the querying hostTop-talker analysis, incident scoping
8XidDNS transaction ID (hex)Matching request and response
9TypeQuery or Response
10OpcodeStandard, Notify, Update, UnknownSeparates dynamic updates and zone notifications from normal lookups
11FlagsHexRaw header flags (hex)For deep protocol analysis
12FlagsCharDecoded flags: Authoritative, Truncated, RecursionDesired, RecursionAvailableReadable version of the above
13ResponseCodeNOERROR, NXDOMAIN, SERVFAIL, …Error-rate reporting, resolution failure hunting
14QuestionTypeRecord type: A, AAAA, MX, PTR, TXT, …TXT volume is a classic tunneling indicator
15QuestionNameQueried name as a normal FQDNThreat-intel matching, top-domain reports
16InformationFree text for Event / Note entries; for Packet detail blocks the TCP/UDP detail header lineReading server messages
17DetailsJSON representation of a Packet detail block; empty otherwiseFull packet inspection without going back to the raw log
18ComputerNameSource server, from -ComputerNameKeeping multi-server datasets attributable

Two things to plan around:

  • Not every column is filled for every row. Only Packet entries have a client IP, a question name and a response code. Note and Event rows carry their text in Information and leave the protocol columns empty. Design your database schema and dashboard filters accordingly.
  • ComputerName is always the last column, even when you do not use -ComputerName. It is then simply empty. This keeps the layout identical across all servers so you can concatenate files from many DNS servers without a column-mapping step.

The Details column

Detail blocks only appear if the DNS server is configured to log full packet details. When they exist, the parser converts them into a single JSON value so the row stays one row:

{
  "Socket": "848",
  "Remote": "addr 10.10.0.11, port 60580",
  "Buflength": "0x10000 (65536)",
  "Message": {
    "XID": "0x0001",
    "OPCODE": "0 (QUERY)",
    "RCODE": "0 (NOERROR)",
    "QUESTION": [ { "Name": "berlin.de", "QTYPE": "A (1)", "QCLASS": "1" } ],
    "ANSWER": []
  }
}

Parsing these blocks costs time and makes the CSV considerably larger. If you do not need them, use -NoDetailsParsing — the column stays present but empty, and conversion gets faster. See Performance.

The statistics files

Statistics are daily aggregates. Use them when you want a trend or a rollup and do not want to move the full record set around — they are orders of magnitude smaller than the data file.

Context statistics (*_Statistic.csv)

Answers: how much of what kind of activity happened per day?

Date;Context;Count;ComputerName
2026-01-20;Event;2;dc01
2026-01-20;Note;2;dc01
2026-01-20;Packet;12;dc01
ColumnMeaning
DateDay, always yyyy-MM-dd
ContextContext name (Packet, Event, Note, …)
CountNumber of records of that context on that day
ComputerNameSource server

Sample files: en-US WithComputerName, en-US NoComputerName, de-DE WithComputerName, de-DE NoComputerName

Packet statistics (*_PacketStatistic.csv)

Answers: who queried what, how often, per day?

Date;ClientIP;Protocol;Direction;QuestionType;Count;ComputerName
2026-01-20;10.0.0.1;UDP;Rcv;A;3;dc01
2026-01-20;10.0.0.1;UDP;Snd;A;3;dc01
2026-01-20;10.0.0.2;UDP;Rcv;A;3;dc01
ColumnMeaning
DateDay, always yyyy-MM-dd
ClientIPQuerying host
ProtocolUDP or TCP
DirectionRcv or Snd
QuestionTypeDNS record type
CountNumber of matching packets that day
ComputerNameSource server

Sample files: en-US WithComputerName, en-US NoComputerName, de-DE WithComputerName, de-DE NoComputerName

Delimiter and date format

Both output types respect -Delimiter (default ;) and -OutputCulture. For anything that will be imported by a machine, write ISO-like timestamps:

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -OutputCulture 'sv-SE'

That yields 2026-01-20 23:00:16, which SQL Server, Power BI and pandas all read without a format hint. Details in Parameters and Options.

3 - Parameters and Options

What each option of Convert-DNSDebugLogFile actually changes, when you need it, and the traps that are easy to walk into.

This page explains the options in plain language and in the order you will typically need them. It is a guide, not a specification — the authoritative, always-current parameter list lives in the command reference and in:

Get-Help Convert-DNSDebugLogFile -Full

The short version

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log"

That single line already gives you sensible behaviour: both data and statistics files, semicolon delimiter, your machine’s date format, header validation on, source log untouched. Everything below is fine-tuning.

OptionDefaultChange it when
-InputFile(required)always
-OutputFileinput path with .csvyou want output somewhere else
-Delimiter;your consumer expects comma, tab or pipe
-ComputerNameemptyyou merge logs from more than one server
-OutputTypeBothyou only want data, or only rollups
-ContextFilterAllyou only care about actual DNS traffic
-InputCulturecurrent culturethe log came from a server with another locale
-OutputCulturecurrent culturea machine will read the CSV
-NoDetailsParsingoffthroughput matters more than packet internals
-CompressOutputoffyou archive or transfer the results
-RemoveSourceFileoffscheduled cleanup, and you trust the output
-SkipHeaderValidationoffthe file is valid but the header is unusual

Input and output

-InputFile

Path to the log to convert. Takes an array, and takes pipeline input — which is why this works:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" | Convert-DNSDebugLogFile

Get-ChildItem emits objects with a FullName property, and -InputFile accepts it by property name (its aliases include FullName, Path, FilePath). No ForEach-Object needed.

Local paths and SMB/UNC paths both work:

Convert-DNSDebugLogFile -InputFile "\\dc01\C$\Administration\Logs\DNSServer\dns.log"

The command can also open a log that DNS Server currently holds open. See active logs below before you rely on that.

-OutputFile

Without it, the CSV lands next to the input file, same base name, .csv extension. With it, you control the target.

-Delimiter

Default is a semicolon, because in locales where the comma is the decimal separator that is what Excel expects. Use -Delimiter "," for tools and databases that assume classic comma-separated values, or -Delimiter "`t" for tab.

Whatever you pick, use the same value on the import side. A mismatch is the number one cause of “everything ended up in one column”.

Labelling and filtering

-ComputerName

Fills the ComputerName column. The column exists either way; this just gives it a value.

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -ComputerName $env:COMPUTERNAME

Always set it when several servers feed one dataset — otherwise you cannot tell afterwards which DC a row came from.

-OutputType

  • CSV — data file only
  • Statistic — the two aggregate files only, no row-level data
  • Both — all three files (default)

Statistic is the fast, small option when you only need daily trends. CSV is right when a downstream system does its own aggregation.

-ContextFilter

A DNS debug log mixes actual query traffic with server-internal chatter. -ContextFilter decides what survives into the output.

# only real DNS traffic
Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -ContextFilter Packet

# traffic plus server events, but no diagnostic notes
Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -ContextFilter Packet, Event
ValueContains
Alleverything (default)
PacketDNS queries and responses — the data most analyses need
Eventserver events, e.g. “The DNS server has started”
Notediagnostic notes and warnings, e.g. socket errors

Additional context types (DSPoll, Init, Lookup, Recurse, Remote, Tombstone) appear under All.

Filtering to Event or Note only populates DateTime, ThreadId, Context and Information — the protocol columns stay empty because those entries simply do not carry that information.

-ContextFilter Packet is the usual choice for security and reporting pipelines: it removes the noise and shrinks the output noticeably.

International logs

DNS Server writes timestamps in the Windows locale of the machine it runs on. A German DC writes 20.01.2026 23:00:16; a US server writes 1/20/2026 11:00:16 PM. If your workstation’s locale differs from the server’s, parsing goes wrong — or, worse, silently swaps day and month.

-InputCulture

Tell the parser which locale the source log uses:

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns-berlin.log" -InputCulture 'de-DE'
CultureLog timestamp format
de-DEDD.MM.YYYY HH:MM:SS
en-USM/D/YYYY H:MM:SS AM/PM
en-GBDD/MM/YYYY HH:MM:SS
sv-SEYYYY-MM-DD HH:MM:SS

Default is the culture of the session running the command. In a mixed-locale estate, set it explicitly rather than relying on that default — and remember that a scheduled task running as SYSTEM may not have the culture you tested with interactively.

-OutputCulture

Controls how timestamps are written to the CSV:

# ISO-like output that SQL Server, Power BI and pandas all understand
Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -OutputCulture 'sv-SE'

# same effect, explicit invariant culture
Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" `
    -OutputCulture ([System.Globalization.CultureInfo]::InvariantCulture)

Rule of thumb: if a human opens the file in Excel, match the local culture. If a machine reads it, use sv-SE or invariant culture and stop worrying about regional settings on the import side.

The two parameters are independent — you can read a Swedish log and write US-formatted output.

Speed and storage

-NoDetailsParsing

If the DNS server logs full packet details, the parser turns each detail block into JSON in the Details column. That is useful, but it is also the most expensive part of the run and it inflates the CSV.

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -NoDetailsParsing

The column stays present but empty; the TCP/UDP detail header line is still available in Information. On logs rich in detail blocks this can cut processing time by 30–50 %. Use it whenever query-level information is enough.

-CompressOutput

Zips the generated CSV files and deletes the uncompressed ones. dns.log produces dns.zip instead of dns.csv.

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -CompressOutput

CSV of this shape typically compresses by 90 % or more, so this is close to free storage savings for archives and for shipping files across the network.

-RemoveSourceFile

Deletes the source .log after a successful conversion — the log is only removed if all output files were created.

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -CompressOutput -RemoveSourceFile

Safety nets

-SkipHeaderValidation

By default the command checks that the file really is a DNS Server debug log before parsing it. This catches the classic mistake of pointing the job at the wrong folder.

Switch it off only for genuinely unusual cases: hand-edited logs, pre-filtered extracts, custom formats. Keep it on everywhere else — it is cheap and it is what stands between a typo and a pile of garbage rows.

-WhatIf and -Confirm

The command supports both. -WhatIf is the right way to see what a new batch job would touch:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" |
    Convert-DNSDebugLogFile -RemoveSourceFile -WhatIf

-Confirm prompts before processing each file, before deleting a source file, and before overwriting existing output.

Active logs

Convert-DNSDebugLogFile can read a file that DNS Server has open. Handy for an ad-hoc look at what is happening right now.

Putting it together

A typical production invocation on a domain controller:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" |
    Sort-Object LastWriteTime -Descending |
    Select-Object -Skip 1 |
    Convert-DNSDebugLogFile `
        -ComputerName $env:COMPUTERNAME `
        -Delimiter ';' `
        -OutputType Both `
        -ContextFilter Packet `
        -OutputCulture 'sv-SE' `
        -CompressOutput

Read as: take every rotated log except the active one, keep only DNS traffic, label each row with the server name, write machine-readable timestamps, and leave compressed archives behind. The full scheduled-task and Group Policy version of this is in the GPO-driven collection example.

4 - Performance

How the parser handles 100 MB logs without eating your server’s memory, and what you can do to keep conversions fast.

DNS debug logs on a busy domain controller are big. Convert-DNSDebugLogFile is built for that case: it has been tested with logs of 100 MB and beyond, and it processes them in minutes on ordinary server hardware.

Why it is fast

You do not need to know any of this to use the module, but it explains the behaviour you will observe.

TechniqueEffect you notice
StreamReader / StreamWriter with 64 KB buffersThe file is read and written in chunks instead of one big Get-Content
Streaming, single passMemory usage stays roughly flat no matter how large the log is
String operations (.Substring(), .IndexOf()) instead of regular expressionsConsiderably less CPU per line, and there are millions of lines
CSV written by hand instead of Export-CsvNo object pipeline overhead per record
Hashtable-based aggregation for statisticsRollups cost almost nothing extra during the same pass

The important consequence: the whole log is never held in memory. A 500 MB log does not need 500 MB of RAM. This is the difference between the module and the “read the file, split it, build objects” approach most home-grown scripts take — that approach works fine on a 5 MB sample and falls over on a real DC.

Getting the most out of a run

Convert rotated chunks, not one giant file

Configure DNS Server to roll the log over at a manageable size — 50 to 200 MB is a good range. Several medium files convert in predictable time and let a scheduled job finish inside its window. One ever-growing file eventually does not.

Rollover also gives you closed files to work with, which is what you want anyway:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" |
    Sort-Object LastWriteTime -Descending |
    Select-Object -Skip 1 |
    Convert-DNSDebugLogFile -ComputerName $env:COMPUTERNAME

Skip detail parsing when you do not need it

If the DNS server writes full packet details, turning those blocks into JSON is the single most expensive part of the conversion.

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -NoDetailsParsing

Expect 30–50 % faster runs on logs that contain many detail blocks, plus a much smaller CSV. You still get the query-level data and the TCP/UDP detail header line in Information. See Parameters and Options.

Filter early

-ContextFilter Packet drops server notes and events before they are written. Less output means less I/O, smaller files, and less work downstream.

Ask only for what you need

-OutputType Statistic skips writing the row-level CSV entirely. If your dashboard only shows daily counts, this is by far the cheapest option.

Convert locally, move the results

The module reads SMB/UNC paths, but pulling a 200 MB raw log across the network to parse it centrally is the slow way round. Convert on the DNS server, then move the (compressed) CSV — that is usually a tenth of the bytes. This is the design behind the GPO-driven collection example.

Compress for transfer and archive

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -CompressOutput

CSV of this shape typically shrinks by 90 % or more. Compression costs a little CPU at the end of the run and saves a lot of disk and network afterwards.

When a run is slower than expected

Check these in order:

  1. Disk, not CPU. Conversion is I/O-heavy. A log sitting on a busy volume, or read over a slow link, dominates the runtime.
  2. Detail blocks. If the log contains full packet details and you did not use -NoDetailsParsing, that is where the time goes.
  3. File size. A single multi-gigabyte log will take a while regardless. Fix this with rollover, not with parameters.
  4. Antivirus. Real-time scanning of both the source log and the generated CSV can double the effective I/O cost. An exclusion for the log directory is a common and reasonable measure.
  5. Memory pressure. The module streams, so it should not be the cause — but a server already swapping will make everything slow.

More symptoms and fixes are collected in Troubleshooting.

5 - Integration with Analysis Tools

Getting the converted CSV into Excel, Power BI, SQL Server, a SIEM, or a Python notebook — including the delimiter and date settings that make it work on the first attempt.

The point of converting a DNS debug log is what happens next. CSV was chosen because everything reads it — but “everything reads CSV” hides two settings that decide whether an import is painless or an afternoon of fiddling.

Two settings that decide everything

Delimiter. Default is ;. Keep it for Excel in locales that use the comma as decimal separator. Switch to , for most databases and data-science tooling. Whatever you choose, tell the importing side the same thing.

Date format. -OutputCulture controls how timestamps are written. For anything read by a machine, use sv-SE (or invariant culture) so DateTime comes out as 2026-01-20 23:00:16:

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -OutputCulture 'sv-SE'

Every consumer below understands that format without a hint. Locale-specific output such as 20.01.2026 will import as text or, worse, get misread as month/day.

Microsoft Excel

The quickest way to look at a single converted log.

  • With the default ; delimiter and a locale that expects it, a double-click opens the file with proper columns.
  • If everything lands in column A, the delimiter does not match your Excel setting. Either re-run with -Delimiter "," or import via Data → From Text/CSV and pick the delimiter there.
  • Turn the range into a table (Ctrl+T) and build a PivotTable on ClientIP, QuestionName or QuestionType. Top-talkers and top-domains take about a minute.
  • For anything over a few hundred thousand rows, use Power Query or one of the other options below instead.

The *_Statistic.csv and *_PacketStatistic.csv files are usually the better Excel targets — they are pre-aggregated and stay small. See Output Formats.

Power BI

Import the CSV files and build dashboards for DNS activity, top clients, query trends, and error rates.

  • Point Power Query at the folder holding your converted files rather than a single file. The layout is identical across servers and days, so files simply append.
  • The ComputerName column is what makes a multi-server report possible — set -ComputerName during conversion or you will not be able to slice by server.
  • ResponseCode and QuestionType are natural slicers; DateTime becomes your time axis.
  • Feeding Power BI with *_PacketStatistic.csv instead of the full data file keeps the model small when you only need daily trends.

SQL databases

Bulk-load the CSV into SQL Server, PostgreSQL, or anything else that speaks SQL, for long-term retention and repeatable queries.

A ready-to-run walkthrough — table definition, conversion, SqlBulkCopy import, and a detection query for suspicious TXT activity — is documented in Security Analysis Workflow with SQL Server.

Points worth planning before the first load:

  • Use -OutputCulture 'sv-SE' so timestamps land in a datetime2 column without conversion tricks.
  • Information and Details can be long; give them nvarchar(max).
  • Index what you actually query — typically DateTime, ClientIP and QuestionName.
  • Keep -ComputerName populated so rows stay attributable after they are merged.

SIEM systems

Splunk, Elastic, Sentinel, and similar platforms ingest the CSV for correlation with other security telemetry and for alerting.

  • Ship the compressed output (-CompressOutput) — it is roughly a tenth of the size and most collectors unpack it themselves.
  • Define the field mapping once; the column layout never changes between runs or servers, including the always-present trailing ComputerName column.
  • Make your collector deduplicate, or archive processed .log files. A conversion job that reprocesses the same rotated logs will otherwise re-send identical rows.
  • -ContextFilter Packet keeps ingest volume (and licence cost) down when server notes are not part of your use cases.

Python, R and data science tooling

The structured output is ready for anomaly detection, baselining, and custom analytics.

import pandas as pd

df = pd.read_csv(
    r"C:\Administration\Logs\DNSServer\dns.csv",
    sep=";",
    parse_dates=["DateTime"],
)

# top 20 queried names, queries only
top = (
    df[df["Direction"] == "Rcv"]
    .groupby("QuestionName")
    .size()
    .sort_values(ascending=False)
    .head(20)
)
print(top)

parse_dates works out of the box when you exported with -OutputCulture 'sv-SE'. From here, pandas, scikit-learn, or R handle clustering, seasonality and outlier detection as usual.

Staying in PowerShell

You do not have to leave PowerShell for a quick answer:

$dns = Import-Csv "C:\Administration\Logs\DNSServer\dns.csv" -Delimiter ';'

# noisiest clients
$dns | Where-Object Direction -eq 'Rcv' |
    Group-Object ClientIP |
    Sort-Object Count -Descending |
    Select-Object -First 10 Count, Name

# failed lookups
$dns | Where-Object ResponseCode -eq 'NXDOMAIN' |
    Group-Object QuestionName |
    Sort-Object Count -Descending |
    Select-Object -First 10 Count, Name

Import-Csv reads the whole file into memory, so this is fine for a rotated chunk and unsuitable for a multi-gigabyte export — that is what the database and SIEM routes are for.

6 - Operational Best Practices

What to get right before you let a DNS log conversion run unattended on production domain controllers.

Converting a log by hand is easy. Running it every night on every domain controller, for years, without anyone looking at it, is the part that needs a bit of design. These are the points that matter in practice.

1. Convert rotated logs, not the active one

Enable log rollover on the DNS server and convert only closed files. The module can read the log DNS Server is currently writing to, but that file changes underneath the conversion: the newest entries may be missing and the last record may be truncated. Two runs produce two different results.

The standard pattern skips the newest file:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" |
    Sort-Object LastWriteTime -Descending |
    Select-Object -Skip 1 |
    Convert-DNSDebugLogFile -ComputerName $env:COMPUTERNAME

Trade-off to be aware of: on a low-volume server, rollover may take longer than a day, so the current day’s data stays unconverted until the file rolls. Size the rollover threshold accordingly.

2. Schedule it, and give the job an identity that works

Task Scheduler is the usual home for this — daily is a sensible default. A full Group Policy implementation for domain controllers is documented in the GPO-driven collection example, and a standalone task in the Scheduled Task example.

Three things bite people here:

  • Module discoverability. A task running as SYSTEM with -NoProfile only sees machine-wide module paths. Install the module machine-wide, or add an explicit Import-Module to the task action.
  • Culture. The account running the task may not have the locale you tested with interactively. Set -InputCulture and -OutputCulture explicitly instead of relying on the default.
  • Network access. If the source or the target is a UNC path, SYSTEM authenticates as the computer account. Grant share and NTFS rights to the computer account (or the Domain Controllers group), or run the task as a dedicated service account.

3. Rotate at a size you can process

50–200 MB per file keeps conversions predictable and lets a nightly job finish inside its window. One file that grows forever eventually does not. See Performance.

4. Validate the first outputs before you automate

Run the conversion manually on two or three real logs and actually open the CSV:

  • Are the timestamps correct — not day/month swapped? (If they are, set -InputCulture.)
  • Does the delimiter match what your consumer expects?
  • Is ComputerName populated?
  • Are the contexts you need present, and the ones you do not need filtered out?

-WhatIf shows you which files a batch would touch before it touches them:

Get-ChildItem "C:\Administration\Logs\DNSServer\*.log" |
    Convert-DNSDebugLogFile -RemoveSourceFile -WhatIf

5. Decide what happens to processed logs

A job that simply converts “every log except the newest” will reprocess the same files every night. That is robust and simple, but it overwrites outputs and can push duplicate rows into whatever ingests them.

Pick one:

  • move processed .log files to an archive folder
  • delete them with -RemoveSourceFile once you trust the pipeline
  • make the downstream collector deduplicate

Whichever you choose, write it down — this is the detail that confuses the next administrator.

6. Plan storage and retention

Compression (-CompressOutput) usually reduces the CSV by 90 % or more, but volume still accumulates. Estimate from your actual query rate and your retention obligation, and set an end date for the data instead of letting it grow indefinitely.

-OutputType Statistic is worth considering for long retention: daily rollups are tiny and often answer the trend questions that old row-level data was being kept for.

7. Treat the output as sensitive

Parsed DNS logs describe your internal name structure and who looked up what. That is more revealing than most infrastructure logs, and depending on your jurisdiction it may count as personal data.

  • Restrict NTFS and share permissions on the output folders.
  • Do not drop CSVs on a general-purpose file share “temporarily”.
  • Include DNS log data in your retention and deletion policy, not just your backup policy.
  • Compressed output is smaller, not protected — use encryption or access control where it matters.

8. Keep header validation on

The default check that a file really is a DNS debug log costs nothing and prevents a mistyped path from producing thousands of nonsense rows. Use -SkipHeaderValidation only for genuinely unusual formats — and note that the command refuses to combine it with -RemoveSourceFile for exactly this reason.

9. Monitor the job, not just the server

An unattended conversion that quietly stops is worse than no conversion, because the gap is only noticed when someone needs the data.

  • Watch for non-zero error output; the GPO reference implementation deliberately throws when $Error.Count -gt 0 so the task reports failure.
  • Alert on the scheduled task’s last result code, not just on whether the task exists.
  • Check that output files are actually appearing with recent timestamps.
  • Watch free disk space on both the log volume and the output target.

Common causes of a failed run — access denied, corrupt logs, invalid headers — are covered in Troubleshooting.

10. Document the workflow

Where logs are written, when the job runs, which parameters are used, where output goes, who consumes it, and how long it is kept. Six lines in your operations wiki. It is what makes the setup auditable and hand-overable.

7 - Troubleshooting

Symptoms you are likely to hit when converting DNS debug logs, what causes them, and how to fix them.

“The file is not a valid DNS debug log file”

The header check rejected the input. Usually the path is simply wrong — a .log file in the same folder that is not the DNS debug log, or a file that only contains a rotated header.

Work through this:

  1. Open the file. A DNS debug log starts with a header line such as Message logging started at … and continues with timestamped query entries.

  2. Confirm that DNS debug logging is actually enabled and writing to the path you expect:

    Get-DnsServerDiagnostics | Select-Object Enable, LogFilePath, MaxMBFileSize
    
  3. If the file genuinely is a DNS log but the header is unusual — hand-edited, pre-filtered, a custom export — bypass the check:

    Convert-DNSDebugLogFile -InputFile "C:\Logs\odd.log" -SkipHeaderValidation
    

Keep the validation enabled everywhere else. Note that -SkipHeaderValidation cannot be combined with -RemoveSourceFile, so an unverified file can never be deleted by the conversion.

Output file is empty or has far fewer rows than expected

Check, in this order:

  • Does the log contain query entries at all? A freshly rotated log can hold nothing but a header if no queries occurred yet.
  • Is a -ContextFilter in play? -ContextFilter Packet removes Event and Note entries by design. If you filtered to Event or Note, most columns will also be empty — those entry types only carry DateTime, ThreadId, Context and Information.
  • Was the source log active? A file DNS Server is still writing to can change during conversion; the newest entries may be missing and the last record may be truncated. Convert a rotated, closed log when you need complete output.
  • Is the file corrupt or truncated? Check the end of the log for a half-written line.

Dates are wrong, shifted, or day and month are swapped

The log was written by a server with a different Windows locale than the session doing the conversion. 20.01.2026 and 01/20/2026 describe the same moment, but only if both sides agree on the format.

# log came from a German server
Convert-DNSDebugLogFile -InputFile "C:\Logs\dns-berlin.log" -InputCulture 'de-DE'

Set -InputCulture explicitly in scheduled jobs rather than relying on the culture of the account that happens to run them. If the output should be machine-readable, add -OutputCulture 'sv-SE'. Details in Parameters and Options.

Everything ends up in one column after import

Delimiter mismatch. The module writes ; by default; your consumer expected , (or vice versa).

Either re-run the conversion with the delimiter the consumer wants:

Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -Delimiter ","

…or tell the importer which delimiter the file uses — in Excel via Data → From Text/CSV, in PowerShell via Import-Csv -Delimiter ';'.

“Access denied”

  • The DNS log directory typically requires administrative rights. Start PowerShell elevated, or run the scheduled task with an account that has access.
  • Check write access to the output directory as well, not just read access to the log.
  • For SMB/UNC paths: a task running as SYSTEM authenticates on the network as the computer account. Grant share and NTFS rights to that computer account (or to the Domain Controllers group), or use a dedicated service account.
  • If -RemoveSourceFile fails at the end of an otherwise successful run, the account can read the log but not delete it.

Processing is very slow

  1. Disk first — conversion is I/O-bound. A busy volume or a slow network path dominates the runtime.
  2. Use -NoDetailsParsing if you do not need the packet-detail JSON; on detail-heavy logs this saves 30–50 %.
  3. Use -ContextFilter Packet to write less.
  4. Break huge logs up with DNS Server log rollover instead of converting one enormous file.
  5. Consider an antivirus exclusion for the log directory.

More in Performance.

Compressed output is larger than expected

Logs with very diverse content — many unique domains, many distinct clients — compress less than repetitive ones. That is normal. ZIP still typically achieves a substantial reduction; if it does not, check whether the Details column is inflating the file and whether you need it at all.

Statistics do not match what I expected

  • Confirm you used -OutputType Both or -OutputType Statistic. With -OutputType CSV, no statistics files are written at all.
  • Count is a total, not a distinct count. One client asking for the same name 500 times contributes 500. This is the most frequent source of “that number cannot be right”.
  • Statistics are grouped per day. A log spanning two days produces rows for both.
  • If ComputerName is empty in the statistics files, -ComputerName was not set during conversion.

The scheduled task works interactively but not as a task

Almost always one of three things:

  • Module not found. SYSTEM with -NoProfile only sees machine-wide module paths. Install the module machine-wide or add an explicit Import-Module DNSServer.DebugLogParser to the task action.
  • Wrong culture. The task account’s locale differs from yours. Set -InputCulture and -OutputCulture explicitly.
  • Execution policy or unsigned script. Match the task’s -ExecutionPolicy to your signing policy, and unblock files copied from elsewhere.

Run the exact task command line manually in the same context (for example with PsExec as SYSTEM) to reproduce it.

Reporting an issue

If none of this helps:

  1. Update to the latest module version and retry.

  2. Search the GitHub issues for the same symptom.

  3. Collect the diagnostics:

    $PSVersionTable
    Get-Module DNSServer.DebugLogParser -ListAvailable | Select-Object Name, Version, Path
    Get-Culture
    

    plus the exact command you ran, the full error message including the stack trace, and — if you can share it — a small anonymised excerpt of the log that reproduces the problem.

  4. Open a new issue with that information.

8 - Module commands reference

Within here, you can find a reference for all commands in the module. This reference is designed to help you quickly find the command you need and understand how to use it effectively.

By clicking on a command, you will be taken to a detailed page that provides comprehensive information about the command, including its syntax, parameters, examples, and any additional notes or tips for usage.

8.1 - Convert-DNSDebugLogFile

SYNOPSIS

Transforms Windows DNS Server debug logs into structured CSV format for analysis and reporting.

SYNTAX

__AllParameterSets

Convert-DNSDebugLogFile [-InputFile] <string[]> [[-OutputFile] <string>] [[-Delimiter] <string>]
 [[-ComputerName] <string>] [[-OutputType] <string>] [[-ContextFilter] <string[]>]
 [[-InputCulture] <cultureinfo>] [[-OutputCulture] <cultureinfo>] [-SkipHeaderValidation]
 [-RemoveSourceFile] [-CompressOutput] [-NoDetailsParsing] [-WhatIf] [-Confirm]

ALIASES

This cmdlet has the following aliases,

DESCRIPTION

Converts Windows DNS Server debug log files into structured CSV data that can be analyzed in Excel, Power BI, SQL databases, or SIEM tools. Designed for security analysis, performance monitoring, troubleshooting, and compliance reporting.

The cmdlet parses DNS debug logs and writes a consistent CSV output for analysis. The CSV output contains 18 columns, including an Information column for event/diagnostic text, an optional Details JSON column for Packet detail blocks, and an always-present ComputerName column (empty unless specified).

KEY FEATURES:

  • Streaming processing avoids loading the full file into memory (suitable for very large logs)
  • High-performance parsing optimized for large files (100MB+)
  • Customizable CSV delimiter (default: semicolon)
  • Optional statistical summaries with aggregated metrics
  • Context filtering (Packet, Event, Note, and additional contexts) to focus on specific log entry types
  • Culture-aware date parsing and formatting for international servers
  • Pipeline support for batch processing multiple files
  • Optional compression of output files (ZIP format)
  • Optional automatic removal of source files after processing
  • Header validation to ensure data integrity

OUTPUT FORMAT: The ComputerName column is always included at the end of each record. If the -ComputerName parameter is not specified, the column will be empty. This ensures consistent output structure for multi-server consolidation scenarios.

PERFORMANCE: Optimized using StreamReader/StreamWriter with 64KB buffers, streaming processing for memory-efficient handling of large files, string operations instead of regex, manual CSV generation, and efficient hashtable-based statistics collection.

COMPATIBILITY:

  • PowerShell 5.1+ (Desktop and Core editions)
  • Windows Server 2016+
  • DNS Server 2012 R2 through 2025 log formats

EXAMPLES

EXAMPLE 1

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log"

Converts the DNS debug log using default settings (both data and statistics files with semicolon delimiter). Output:

  • C:\Logs\dns.csv
  • C:\Logs\dns_Statistic.csv
  • C:\Logs\dns_PacketStatistic.csv

EXAMPLE 2

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -OutputType CSV

Generates only the data file without statistics. Output: C:\Logs\dns.csv

EXAMPLE 3

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -OutputType Statistic

Generates only the statistics file with aggregated metrics. Output:

  • C:\Logs\dns_Statistic.csv
  • C:\Logs\dns_PacketStatistic.csv

EXAMPLE 4

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -OutputFile "C:\Output\parsed.csv"

Converts the log to a custom output location. Output: C:\Output\parsed.csv

EXAMPLE 5

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -Delimiter "," -ComputerName "DNS01" -OutputType Both

Converts with comma delimiter and adds ComputerName column with value “DNS01”. Output:

  • C:\Logs\dns.csv
  • C:\Logs\dns_Statistic.csv
  • C:\Logs\dns_PacketStatistic.csv

EXAMPLE 6

PS C:\> Get-ChildItem "C:\Logs\*.log" | Convert-DNSDebugLogFile -OutputType Both

Batch processes multiple DNS debug log files via pipeline. Output: For each .log file, generates .csv and _statistic.csv files

EXAMPLE 7

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -CompressOutput

Converts and compresses output to ZIP archive. Output: C:\Logs\dns.zip (containing dns.csv + statistics files)

EXAMPLE 8

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -RemoveSourceFile -Verbose

Converts the log and removes the source file after successful processing. Verbose output confirms file removal.

EXAMPLE 9

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -InputCulture 'de-DE' -OutputCulture 'en-US'

Parses German date format (DD.MM.YYYY) and outputs in US format (MM/DD/YYYY). Use when processing logs from servers with different regional settings.

EXAMPLE 10

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -ContextFilter 'Packet'

Converts only DNS query/response packet entries, excluding EVENT and Note entries. Use to focus analysis on actual DNS traffic.

EXAMPLE 11

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\dns.log" -ContextFilter 'Packet','Event'

Converts both DNS query/response packets and server events, excluding Note and other entries. Use to analyze DNS traffic along with server event context.

EXAMPLE 12

PS C:\> Get-ChildItem "C:\Logs\*.log" | Convert-DNSDebugLogFile -RemoveSourceFile -CompressOutput

Automated log archival: processes all logs, compresses output, and removes source files. Ideal for scheduled log processing pipelines.

EXAMPLE 13

PS C:\> Convert-DNSDebugLogFile -InputFile "C:\Logs\large-dns.log" -NoDetailsParsing

Processes a large log file with detail parsing disabled for maximum performance. PACKET detail blocks are skipped, keeping the Details column empty. Use when processing very large files and detailed packet structure is not needed.

PARAMETERS

-CompressOutput

Compresses output CSV files into a ZIP archive after creation.

Creates a .zip file containing the generated CSV file(s), then removes the uncompressed CSV(s). The ZIP file is created in the same directory as the output CSV with the same base name.

Benefits:

  • Significantly reduces disk space (CSV files typically compress 90%+)
  • Simplifies file management and archival
  • Suitable for long-term storage

Example: Input ‘dns.log’ generates ‘dns.csv’ compressed to ‘dns.zip’, then ‘dns.csv’ is removed.

Type: SwitchParameter
DefaultValue: False
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: Named
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-ComputerName

Specifies the value for the ComputerName column in the CSV output. The ComputerName column is always present in the output - if this parameter is not specified, the column will be empty.

Use this when consolidating logs from multiple DNS servers to identify the source server in combined datasets.

Note: This is NOT a remoting parameter. It only labels the output. If you point -InputFile to a UNC path, the file is read from that path (no WinRM/remote execution is performed).

Type: String
DefaultValue: ''
SupportsWildcards: false
Aliases:
- Server
- DNSServer
- HostName
ParameterSets:
- Name: (All)
  Position: 3
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-Confirm

Prompts you for confirmation before running the cmdlet.

When specified, prompts for confirmation before:

  • Processing each DNS debug log file
  • Removing source files (when -RemoveSourceFile is specified)
  • Overwriting existing output files

Useful for interactive processing when you want to control which files are processed.

Type: SwitchParameter
DefaultValue: ''
SupportsWildcards: false
Aliases:
- cf
ParameterSets:
- Name: (All)
  Position: Named
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-ContextFilter

Filters which log entry types to include in the output. Accepts single or multiple values.

DNS debug logs contain different context types:

  • PACKET: DNS query and response packet information (primary data)
  • EVENT: DNS server events (e.g., “The DNS server has started.”)
  • Note: Diagnostic notes and warnings (e.g., socket errors, internal states)
  • DSPoll, Init, Lookup, Recurse, Remote, Tombstone: Additional context types

Valid values:

  • ‘All’: Include all context types (default)
  • ‘Packet’: Include only PACKET entries (DNS queries/responses)
  • ‘Event’: Include only EVENT entries (server events)
  • ‘Note’: Include only Note entries (diagnostic information)
  • Any combination: Specify multiple values to include specific context types

Default: All

Examples:

  • ‘Packet’ filters to only DNS traffic
  • ‘Packet’,‘Event’ includes both DNS traffic and server events
  • ‘Note’,‘Event’ includes diagnostic notes and server events

Note: When filtering to ‘Event’ or ‘Note’, only DateTime, ThreadId, Context, and Information columns will contain data. Other columns (Protocol, ClientIP, etc.) will be empty.

Type: String[]
DefaultValue: "@('All')"
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: 5
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-Delimiter

Specifies the delimiter character for the CSV output.

Default: Semicolon (;)

Common alternatives: Comma (,), Tab (`t), Pipe (|)

Use semicolon in regions where comma is the decimal separator (Europe). Use comma for standard CSV tools and databases that expect comma-separated values.

Type: String
DefaultValue: ;
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: 2
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-InputCulture

Specifies the culture/locale to use for parsing date/time values in the DNS debug log.

DNS Server debug logs use the date format of the Windows locale on the server where the log was generated. Use this parameter when processing logs from servers with different regional settings.

Default: Current culture

Common examples:

  • ‘de-DE’ or ‘de-AT’: German format (DD.MM.YYYY or DD/MM/YYYY)
  • ’en-US’: US format (MM/DD/YYYY with AM/PM)
  • ’en-GB’: UK format (DD/MM/YYYY with 24-hour time)
  • ‘sv-SE’: Swedish/ISO format (YYYY-MM-DD)
Type: CultureInfo
DefaultValue: '[System.Globalization.CultureInfo]::CurrentCulture'
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: 6
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-InputFile

Specifies the path to the DNS debug log file to parse. Supports arrays for processing multiple files.

Accepts pipeline input from Get-ChildItem or other file-producing cmdlets.

Type: String[]
DefaultValue: ''
SupportsWildcards: false
Aliases:
- FullName
- FilePath
- InputPath
- File
- Path
ParameterSets:
- Name: (All)
  Position: 0
  IsRequired: true
  ValueFromPipeline: true
  ValueFromPipelineByPropertyName: true
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-NoDetailsParsing

Skips parsing PACKET detail blocks into structured JSON format.

When specified, PACKET records with detail blocks will have the TCP/UDP info line in the Information column, but the Details column will remain empty. This significantly improves processing performance for large log files when detailed packet structure analysis is not needed.

Use this switch when:

  • Processing very large log files (100MB+) and only need basic query information
  • Detail structure (Message flags, DNS sections) is not required for analysis
  • Maximizing parsing speed is more important than data completeness

Performance impact: Can improve processing speed by 30-50% for logs with many PACKET detail blocks.

Type: SwitchParameter
DefaultValue: False
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: Named
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-OutputCulture

Specifies the culture/locale to use for formatting date/time values in the output CSV files.

Controls how DateTime values are written to the CSV. Use this when CSV files will be consumed by applications or systems with specific regional settings.

Default: Current culture

Common examples:

  • ’en-US’: US format (MM/DD/YYYY)
  • ‘de-DE’: German format (DD.MM.YYYY)
  • ‘sv-SE’ or InvariantCulture: ISO format (YYYY-MM-DD) for maximum compatibility
Type: CultureInfo
DefaultValue: '[System.Globalization.CultureInfo]::CurrentCulture'
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: 7
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-OutputFile

Specifies the path for the output CSV file. If not specified, uses the input filename with .csv extension in the same directory as the input file.

Important: Must be a file path, not a directory. If you want to use the input file’s directory with a custom name, specify the full path including filename.

Type: String
DefaultValue: ''
SupportsWildcards: false
Aliases:
- Output
- Destination
- OutFile
- OutputPath
ParameterSets:
- Name: (All)
  Position: 1
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-OutputType

Specifies the type of output to generate.

Valid values:

  • ‘CSV’: Generate only the data file with all parsed log entries
  • ‘Statistic’: Generate only the statistics files with aggregated metrics
  • ‘Both’: Generate both data and statistics files (default)

Default: Both

When statistics are generated, two separate files are created:

  • ‘_Statistic.csv’: Summary counts per context type per day (Date, Context, Count, ComputerName)
  • ‘_PacketStatistic.csv’: Detailed PACKET counts per day by client IP, protocol, direction, and query type (Date, ClientIP, Protocol, Direction, QuestionType, Count, ComputerName)
Type: String
DefaultValue: Both
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: 4
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-RemoveSourceFile

Removes the source DNS debug log file after successful processing.

Use this for automated log processing pipelines or disk space management. The source file is only removed if processing completes successfully and all output files are created.

Safety: Cannot be used with -SkipHeaderValidation to prevent accidental deletion of invalid files.

Warning: Source files are permanently deleted. Ensure output files are valid before using this option.

Type: SwitchParameter
DefaultValue: False
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: Named
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-SkipHeaderValidation

Bypasses the DNS debug log header validation check.

By default, the cmdlet validates that input files have a valid DNS Server debug log header. Use this switch to process files without validation, which can be useful for:

  • Modified or custom log formats
  • Troubleshooting validation issues
  • Non-standard or pre-processed logs

Warning: May result in processing errors if the file is not a valid DNS log.

Type: SwitchParameter
DefaultValue: False
SupportsWildcards: false
Aliases: []
ParameterSets:
- Name: (All)
  Position: Named
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

-WhatIf

Shows what would happen if the cmdlet runs. The cmdlet is not run.

When specified, displays detailed information about the operations that would be performed without actually executing them. Useful for:

  • Previewing which files would be processed
  • Verifying output file paths before processing
  • Testing scripts before running in production
Type: SwitchParameter
DefaultValue: ''
SupportsWildcards: false
Aliases:
- wi
ParameterSets:
- Name: (All)
  Position: Named
  IsRequired: false
  ValueFromPipeline: false
  ValueFromPipelineByPropertyName: false
  ValueFromRemainingArguments: false
DontShow: false
AcceptedValues: []
HelpMessage: ''

CommonParameters

This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutBuffer, -OutVariable, -PipelineVariable, -ProgressAction, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters.

INPUTS

System.String[]

NOTES

Version : 1.7.2.1 Author : Andi Bellstedt, Copilot, Patrick Charbonnier (Silent Waters IT Consulting S.L.) Date : 2026-07-24 Keywords : Microsoft Windows Server, DNSServer, DNS, DebugLog, LogParser

9 - Usage Examples

Here you can find practical examples of how to use the module in real-world scenarios. These examples are designed to help you understand how to apply the module’s functionality.

These are examples with a little more depth and context. If you want to just the usage of the commands from the module, check out the command reference.

9.1 - Practical usage in a Domain Environment (GPO-driven collection and conversion)

This example demonstrates how to implement a GPO-driven workflow for collecting and converting DNS debug logs on domain controllers.

This document outlines a practical, end-to-end example of running DNSServer.DebugLogParser in an Active Directory domain environment, focused on converting Windows DNS Server debug logs on domain controllers.

This example is accompanied by a ZIP archive, which provide the policy artifacts used to implement the workflow described here.
The most relevant artifacts are backup manifest, GPO report, Files.xml, Set-DNSServerDebugLogging.ps1, and ScheduledTasks.xml.

Scenario

  • Multiple domain controllers (DCs) host the DNS Server role.
  • DNS debug logging is enabled and configured consistently on each DC via a scheduled task (writing log files to C:\Administration\Logs\DNSServer).
  • A centrally managed process converts logs into CSV for:
    • security analytics
    • operational reporting
    • troubleshooting
    • compliance/retention

Target outcomes

  • Consistent conversion settings across all DCs
  • Predictable output location and naming
  • Optional compression to reduce storage footprint
  • Optional statistics outputs for quick daily rollups
  • Minimal host-side risk, with explicit rerun and cleanup considerations

Suggested architecture

Collection model: local convert + central pull

  1. Each DC writes DNS debug logs to disk with rollover enabled.
  2. Each DC converts rotated *.log files into a data CSV and statistics CSVs, then compresses the outputs into *.zip on a schedule (Task Scheduler).
  3. Outputs are written next to the log files so the pipeline stays simple.
  4. A central server collects the *.zip outputs, for example via file share ingestion, scheduled copy, SIEM forwarder, or an agent-based collector.

This model minimizes network reads of large raw log files and keeps parsing close to the data.

GPO workflow

The workflow is implemented through Group Policy (computer configuration) to ensure consistent settings across all domain controllers.

Reference implementation included in this repository (GPO report):

  • Archive/report name: T0-C-Analytics-DNSDebugLogging
  • Backup ID: {2B6F16BC-0E7C-4787-83D7-2854FED882EE}
  • GPO link target: corp.company.com/Domain Controllers
  • Item filter (used for both file deployment and scheduled tasks): only applies if C:\Windows\System32\dns.exe exists

1) Prerequisites (folders + module)

The provided backup assumes these folders already exist. Add separate GPP items if you want the deployment to create them automatically:

  • C:\Administration\Scripts
  • C:\Administration\Logs\DNSServer

The provided backup also assumes Convert-DNSDebugLogFile is already available on the DCs. The conversion task starts Windows PowerShell 5.1 with -NoProfile and does not import the module explicitly, so the module must be installed in a machine-wide Windows PowerShell module path that is visible to LocalSystem. Recommended approaches:

  • Install DNSServer.DebugLogParser on the DCs. For example, from PowerShell Gallery (if policy allows).
  • Deploy the module via internal repo / file share so it is discoverable in $env:PSModulePath
  • Add an explicit Import-Module to the task action if you want deterministic loading behavior

2) Deploy the debug logging configuration script (GPP Files)

The GPO deploys the script:

  • Source (in SYSVOL via GPP): %GptPath%\Preferences\Files\Set-DNSServerDebugLogging.ps1
  • Target (on each DC): C:\Administration\Scripts\Set-DNSServerDebugLogging.ps1

This is implemented in the GPP Files preference item in Files.xml.

3) Scheduled task: configure DNS debug logging

The GPO creates a scheduled task named Set-DNSServerDebugLogging.

  • Security context in the supplied backup: SYSTEM with logon type S4U
  • Trigger in the supplied backup: daily (start boundary 2025-03-01T00:00:01)
  • Action in ScheduledTasks.xml:
    • powershell.exe -ExecutionPolicy RemoteSigned -command " & { C:\Administration\Scripts\Set-DNSServerDebugLogging.ps1 }"
    • Working directory: C:\Administration\Scripts

The linked Set-DNSServerDebugLogging.ps1 script configures DNS debug logging via Get-DnsServerDiagnostics / Set-DnsServerDiagnostics and (notably):

  • Enables logging to file + rollover
  • Writes to: C:\Administration\Logs\DNSServer\DnsDebugLog_<COMPUTERNAME>.<Domain>_.log
  • Uses a 10 MB rollover size per file
  • Captures primarily query-related activity (queries + notifications + updates + question transactions) and excludes full packet logging

4) Scheduled task: convert rotated debug logs to compressed CSV

The GPO creates a scheduled task named Convert-DNSDebugLogs.

  • Security context in the supplied backup: SYSTEM with logon type InteractiveToken
  • Trigger in the supplied backup: daily (start boundary 2026-01-01T00:30:00)
  • Working directory: C:\Administration\Logs\DNSServer
  • Action in ScheduledTasks.xml (formatted for readability):
Get-ChildItem .\*.log |
  Sort-Object lastwritetime, Name -Descending |
  Select-Object -Skip 1 |
  Convert-DNSDebugLogFile `
    -ComputerName $env:COMPUTERNAME `
    -Delimiter ';' `
    -OutputType Both `
    -ContextFilter Packet `
    -OutputCulture sv-SE `
    -CompressOutput

Design notes:

  • Select-Object -Skip 1 intentionally avoids processing the newest (active) log file. Convert-DNSDebugLogFile is able to read a log that DNS Server currently has open, but that file changes while it is being read: the output can miss the newest entries or end with a truncated record, and two runs do not produce identical results. Skipping the active file keeps the scheduled output reproducible.
  • That means current data is exported only after rollover; on low-volume DCs, the active log may stay unprocessed for more than a day. Lower the rollover size if that delay is too long for your use case.
  • Because Convert-DNSDebugLogFile defaults -OutputFile to “same folder, same name, .csv”, outputs land next to the *.log inputs.
  • With -CompressOutput, each processed log produces a *.zip and the intermediate CSVs are removed.
  • Unless you archive or delete processed *.log files, later runs will reprocess every non-active log again.
  • The task throws if $Error.Count -gt 0 to signal a failed run.

5) Central ingestion

Options (pick one):

  • File share ingestion: DC writes (or copies) C:\Administration\Logs\DNSServer\*.zip to \\fileserver\share\dns\$env:COMPUTERNAME\... (grant share and NTFS rights to the DC computer accounts or the Domain Controllers group if the task runs as SYSTEM)
  • Pull model: central job reads \\dc\C$\Administration\Logs\DNSServer\*.zip (least preferred; requires admin shares)
  • Agent forwarder: SIEM / log pipeline that ships the *.zip outputs

Operational considerations

  • Least privilege: tasks run as SYSTEM; ensure the local folders are writable and that any UNC targets grant access to the computer account if used.
  • Signing policy: both tasks use -ExecutionPolicy RemoteSigned; sign or unblock the deployed script and module according to your policy.
  • Disk usage: -CompressOutput helps significantly, but this workflow does not remove source logs; plan retention and cleanup.
  • Re-processing behavior: unless you archive or delete processed logs, the conversion task will process every non-active *.log file again on later runs. This is simple and robust, but it can overwrite outputs and create duplicate downstream ingestion if your collector does not deduplicate.
  • Multi-DC consolidation: -ComputerName $env:COMPUTERNAME is included so consolidated datasets remain traceable. Note that -ComputerName only labels the output — it performs no remote connection.
  • Network shares: Convert-DNSDebugLogFile can read source logs from SMB/UNC paths, but converting locally and shipping the compressed results stays the better pattern for large raw logs. If you do use a UNC path, remember that a task running as SYSTEM authenticates on the network as the computer account and needs share plus NTFS rights there.
  • Date format: -OutputCulture sv-SE is used deliberately so timestamps are written as 2026-01-20 23:00:16. That format is read without a hint by SQL Server, Power BI and most import tooling, regardless of the locale of the DC that produced the log.
  • Validation: header validation remains enabled because the task does not use -SkipHeaderValidation (recommended).

Validate and adapt (using the ZIP)

Use the ZIP archive as the reference implementation, then align the following aspects to your environment:

  • Target scope: which DCs / OUs receive the policy
  • Execution identity: confirm both scheduled tasks use the intended logon type (S4U vs InteractiveToken) or normalize them to your standard
  • Folder creation: decide whether C:\Administration\Scripts and C:\Administration\Logs\DNSServer are pre-staged elsewhere or should be created by additional GPP items
  • Paths: confirm C:\Administration\Scripts and C:\Administration\Logs\DNSServer match your standards
  • Retention: decide whether to keep raw logs and for how long (especially if enabling cleanup options)
  • Ingestion: confirm where CSV/ZIP outputs are written and how they are collected centrally

If you want to validate the exact GPO configuration without importing it, the authoritative sources in this repo are:

9.2 - Scheduled Task Example

This example demonstrates how to create a Windows Scheduled Task that runs a PowerShell script to process DNS debug logs daily.

This script creates a Windows Scheduled Task that runs daily at 2:00 AM. It imports the module and processes all the log file in the folder where the script is executed (in this example “C:\Administration\Logs\DNS”). The process does compress the output into ZIP-files and removes the original to maintain hygiene.

$actionParams = @{
    Execute = "powershell.exe"
    Argument = '-ExecutionPolicy RemoteSigned -Command "Import-Module DNSServer.DebugLogParser; Get-ChildItem .\*.log | Sort-Object lastwritetime, Name -Descending | Convert-DNSDebugLogFile -ComputerName $env:COMPUTERNAME -Delimiter \";\" -OutputType Both -ContextFilter Packet -OutputCulture sv-SE -CompressOutput"'
    WorkingDirectory = "C:\Administration\Logs\DNS"
}
$Action = New-ScheduledTaskAction @actionParams

$Trigger = New-ScheduledTaskTrigger -Daily -At "2:00AM"

Register-ScheduledTask -TaskName "Process DNS Logs" -Action $Action -Trigger $Trigger -Description "Convert DNS debug logs to CSV daily"

9.3 - Security Analysis Workflow with SQL Server

Convert DNS debug logs to CSV with DNSServer.DebugLogParser, import the result into SQL Server, and run a simple detection query for suspicious TXT record activity.

This example shows a practical workflow for security analytics: parse a DNS debug log with Convert-DNSDebugLogFile, import the generated CSV into SQL Server, and run a query that highlights unusually high volumes of TXT record lookups.

For best interoperability, this example writes timestamps in an ISO-like format by using -OutputCulture 'sv-SE'.

Required modules

This example uses the following PowerShell modules:

  • DNSServer.DebugLogParser
  • SqlServer

Install them if needed:

Install-Module -Name DNSServer.DebugLogParser -Scope CurrentUser
Install-Module -Name SqlServer -Scope CurrentUser

Scenario

Use this workflow when you want to move parsed DNS debug log data into SQL Server so you can:

  • search large datasets efficiently
  • build repeatable detection queries
  • correlate activity across multiple DNS servers
  • retain normalized data for later investigation

Output of the conversion step

Convert-DNSDebugLogFile does not write directly to SQL Server. It first creates a CSV file. That CSV file is the dataset imported into the database.

In this example:

  • input log: C:\Administration\Logs\DNS\dns.log
  • generated CSV: C:\Administration\Logs\DNS\dns.csv
  • destination table: dbo.DNSQueries

Create the target table

Run the following statement once in SQL Server to create the target table.

IF OBJECT_ID('dbo.DNSQueries', 'U') IS NULL
BEGIN
    CREATE TABLE dbo.DNSQueries (
        DateTime      datetime2(0)   NOT NULL,
        ThreadId      int            NULL,
        Context       nvarchar(20)   NULL,
        PacketId      int            NULL,
        Protocol      nvarchar(10)   NULL,
        Direction     nvarchar(10)   NULL,
        ClientIP      nvarchar(64)   NULL,
        Xid           nvarchar(16)   NULL,
        Type          nvarchar(16)   NULL,
        Opcode        nvarchar(16)   NULL,
        FlagsHex      nvarchar(16)   NULL,
        FlagsChar     nvarchar(16)   NULL,
        ResponseCode  nvarchar(32)   NULL,
        QuestionType  nvarchar(32)   NULL,
        QuestionName  nvarchar(512)  NULL,
        Information   nvarchar(max)  NULL,
        Details       nvarchar(max)  NULL,
        ComputerName  nvarchar(256)  NULL
    );
END;

Convert the log and import the CSV

The following PowerShell example performs the full workflow:

  1. imports the required modules
  2. converts the DNS debug log to CSV
  3. loads the generated CSV
  4. bulk imports the rows into SQL Server
# Requires -Modules DNSServer.DebugLogParser, SqlServer

Import-Module -Name DNSServer.DebugLogParser -ErrorAction Stop
Import-Module -Name SqlServer -ErrorAction Stop

$logPath = 'C:\Administration\Logs\DNS\dns.log'
$csvPath = 'C:\Administration\Logs\DNS\dns.csv'
$serverInstance = 'SQLServer'
$databaseName = 'DNSLogs'
$delimiter = ';'

$createTableSql = @'
IF OBJECT_ID('dbo.DNSQueries', 'U') IS NULL
BEGIN
    CREATE TABLE dbo.DNSQueries (
        DateTime      datetime2(0)   NOT NULL,
        ThreadId      int            NULL,
        Context       nvarchar(20)   NULL,
        PacketId      int            NULL,
        Protocol      nvarchar(10)   NULL,
        Direction     nvarchar(10)   NULL,
        ClientIP      nvarchar(64)   NULL,
        Xid           nvarchar(16)   NULL,
        Type          nvarchar(16)   NULL,
        Opcode        nvarchar(16)   NULL,
        FlagsHex      nvarchar(16)   NULL,
        FlagsChar     nvarchar(16)   NULL,
        ResponseCode  nvarchar(32)   NULL,
        QuestionType  nvarchar(32)   NULL,
        QuestionName  nvarchar(512)  NULL,
        Information   nvarchar(max)  NULL,
        Details       nvarchar(max)  NULL,
        ComputerName  nvarchar(256)  NULL
    );
END
'@

Convert-DNSDebugLogFile `
    -InputFile $logPath `
    -ComputerName 'DNS01' `
    -OutputType CSV `
    -OutputFile $csvPath `
    -Delimiter $delimiter `
    -OutputCulture 'sv-SE'

$rows = Import-Csv -Path $csvPath -Delimiter $delimiter

if (-not $rows) {
    throw "The generated CSV file '$csvPath' does not contain any rows."
}

$dataTable = [System.Data.DataTable]::new()
foreach ($columnName in $rows[0].PSObject.Properties.Name) {
    $null = $dataTable.Columns.Add($columnName, [string])
}

foreach ($row in $rows) {
    $dataRow = $dataTable.NewRow()
    foreach ($column in $dataTable.Columns) {
        $columnName = $column.ColumnName
        $dataRow[$columnName] = $row.$columnName
    }

    $null = $dataTable.Rows.Add($dataRow)
}

$connectionString = "Server=$serverInstance;Database=$databaseName;Integrated Security=True"
$connection = [System.Data.SqlClient.SqlConnection]::new($connectionString)

try {
    $connection.Open()

    $command = $connection.CreateCommand()
    $command.CommandText = $createTableSql
    $null = $command.ExecuteNonQuery()

    $bulkCopy = [System.Data.SqlClient.SqlBulkCopy]::new($connection)
    $bulkCopy.DestinationTableName = 'dbo.DNSQueries'

    foreach ($column in $dataTable.Columns) {
        $null = $bulkCopy.ColumnMappings.Add($column.ColumnName, $column.ColumnName)
    }

    $bulkCopy.WriteToServer($dataTable)
}
finally {
    $connection.Dispose()
}

Query for suspicious TXT record activity

Once the data is in SQL Server, you can search for clients that issue unusually high numbers of TXT record queries.

SELECT
    ComputerName,
    ClientIP,
    QuestionName,
    COUNT(*) AS QueryCount
FROM dbo.DNSQueries
WHERE QuestionType = 'TXT'
GROUP BY
    ComputerName,
    ClientIP,
    QuestionName
HAVING COUNT(*) > 100
ORDER BY QueryCount DESC;

If you prefer to run the query from PowerShell, use Invoke-Sqlcmd from the SqlServer module:

$query = @'
SELECT
    ComputerName,
    ClientIP,
    QuestionName,
    COUNT(*) AS QueryCount
FROM dbo.DNSQueries
WHERE QuestionType = 'TXT'
GROUP BY
    ComputerName,
    ClientIP,
    QuestionName
HAVING COUNT(*) > 100
ORDER BY QueryCount DESC;
'@

Invoke-Sqlcmd `
    -ServerInstance 'SQLServer' `
    -Database 'DNSLogs' `
    -Query $query

Why TXT queries are interesting

High volumes of TXT record lookups can be worth reviewing because they may indicate:

  • DNS tunneling
  • data exfiltration over DNS
  • abuse of TXT records by malware or tooling
  • unusually noisy or misconfigured clients

This query is only a starting point. In production, you should tune the threshold and add filters that match your environment.

Operational notes

  • Import-Csv reads the full file into memory. For very large log exports, consider a streaming approach instead of building a full DataTable.
  • Keep -ComputerName in the conversion step so records remain attributable after central ingestion.
  • Use a consistent delimiter and culture during export and import.
  • Validate retention, indexing, and access control in SQL Server before using this workflow for long-term storage.