NetLogon.log: Control what goes in, and get what you want out

Or, when you want some, but not all, of what Netlogon.log has to offer – especially when trying to track down the source of a user account’s lockouts or find subnets that haven’t been put into an Active Directory site yet.

At one point, we had Netlogon turned up to 11 on all our domain controllers – that is, DBFlag is set to 0x2080ffff, just like this TechNet article and everything else you see at first glance on the Internet has it. That quick looks makes it look like your options are EVERYTHING!!1!1 or nothing. Since that one Knowledge Base article literally IS the only place on the Internet where these flags are listed in detail, and Microsoft has recently started featuring the automated “Fix It” solution, here is the info for posterity (and convenience),
nicely formatted into tables.

Data Source:
Formatting into tables: Amanda Debler (me)
All descriptions as-is from Microsoft.

Basic Netlogon Flags

Flag Name Value Description
NL_INIT 0x00000001 Initialization
NL_MISC 0x00000002 Misc debug
NL_LOGON 0x00000004 Logon processing
NL_SYNC 0x00000008 Synchronization and replication
NL_MAILSLOT 0x00000010 Mailslot messages
NL_SITE 0x00000020 Sites
NL_CRITICAL 0x00000100 Only real important errors
NL_SESSION_SETUP 0x00000200 Trusted Domain maintenance
NL_DOMAIN 0x00000400 Hosted Domain maintenance
NL_2 0x00000800
NL_SERVER_SESS 0x00001000 Server session maintenance
NL_CHANGELOG 0x00002000 Change Log references
NL_DNS 0x00004000 DNS name registration

Verbose Netlogon Flags

Flag Name Value Description
NL_WORKER 0x00010000 Debug worker thread
NL_DNS_MORE 0x00020000 Verbose DNS name registration
NL_PULSE_MORE 0x00040000 Verbose pulse processing
NL_SESSION_MORE 0x00080000 Verbose session management
NL_REPL_TIME 0x00100000 replication timing output
NL_REPL_OBJ_TIME 0x00200000 replication objects get/set timing output
NL_ENCRYPT 0x00400000 debug encrypt and decrypt across net
NL_SYNC_MORE 0x00800000 additional replication dbgprint
NL_PACK_VERBOSE 0x01000000 Verbose Pack/Unpack
NL_MAILSLOT_TEXT 0x02000000 Verbose Mailslot messages
NL_CHALLENGE_RES 0x04000000 challenge response debug
NL_SITE_MORE 0x08000000 Verbose sites

Netlogon Control Flags

Flag Name Value Description
NL_INHIBIT_CANCEL 0x10000000 Don’t cancel API calls
NL_TIMESTAMP 0x20000000 TimeStamp each output line
NL_ONECHANGE_REPL 0x40000000 Only replicate one change per call
NL_BREAKPOINT 0x80000000 Enter debugger on startup

Right now, I just want a clear look at account lockouts and subnetless IPs, even on our busiest DCs. A very busy DC can blow through a 100MB log file allowance in a few hours, and even with Netlogon.bak, collection and filtering would have to happen several times a day to make sure we see all the bad logons.

“But why would you want to capture LESS diagnostic information?!?” Because heavy logging can cause its own problems – read and think about this article from the Directory Services team before you implement “All Logging, All The Time”. It explains how to enable (and disable) logging for all facets of Directory Services.

As a compromise, I’m just going to turn off all those ‘[SITE]’ messages, since they are most of the entries in netlogon.log, and don’t provide any information I need right now. So, 0x2080ffff - 0x00000020 = 0x2080ffdf. I tried the nice .NET/PowerShell way, but it failed against a 2003 server. Back to the old-fashioned way – still possible from within a PowerShell script:

(all one line) reg add "\\$computerName\HKLM\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters" /v DBFlag /t REG_DWORD /d 0x2080ffdf /f

Make sure that your log file is the size you want it to be (in this case, 100 megabytes):

(all one line)reg add "\\$computerName\HKLM\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters" /v MaximumLogFileSize /t REG_DWORD /d 100000000 /f

And to check our work…

(all one line) reg query "\\$computerName\HKLM\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters" /v DBFlag

(all one line) reg query "\\$computerName\HKLM\SYSTEM\CurrentControlSet\Services\NetLogon\Parameters" /v MaximumLogFileSize

Finish up by stopping and starting the Netlogon service, again, the old-fashioned way with NT Service Controller. You need to use sc.exe in PowerShell, because sc is an alias for Set-Content:

sc.exe \\$computerName stop netlogon

sc.exe \\$computerName start netlogon

Here’s a table of the result codes to interpret the [LOGON] entries (from Section “Netlogon Log File Error Codes”, copied in case that particular link goes away):

Log Code Description
0x0 Successful login
0xC0000064 The specified user does not exist
0xC000006A The value provided as the current password is not correct
0xC000006C Password policy not met
0xC000006D The attempted logon is invalid due to a bad user name
0xC000006E User account restriction has prevented successful login
0xC000006F The user account has time restrictions and may not be logged onto at this time
0xC0000070 The user is restricted and may not log on from the source workstation
0xC0000071 The user account’s password has expired
0xC0000072 The user account is currently disabled
0xC000009A Insufficient system resources
0xC0000193 The user’s account has expired
0xC0000224 User must change his password before he logs on the first time
0xC0000234 The user account has been automatically locked

The most important ones to distinguish between are 0xC000006A (bad password was entered this time – these ARE the droids you’re looking for) and 0xC0000234 (a logon attempt has been made with a user account that has been locked out, but this says nothing about whether this current attempt used a good or bad password)

The cmdlet I use to collect NetLogon logs for analysis on my local machine. It must be used in an Powershell instance that was started as a Domain Admin or other account with access to the DC’s %Windows%\Debug directory. Combine in a pipeline with a list of your DCs to speed it up.

function Get-NetLogonLog {
  if (-not (Test-Path $destinationPath) ) {
   New-Item -Path $destinationPath -ItemType Directory
  if (Test-Path "\\$computerName\c$\WINDOWS\Debug\Netlogon.log") {
      Copy-Item -Path "\\$computerName\c$\WINDOWS\Debug\Netlogon.log" -Destination "$destinationPath\$computerName-Netlogon.log"
  elseif (Test-Path "\\$computerName\c$\WINNT\Debug\Netlogon.log") {
    Copy-Item -Path "\\$computerName\c$\WINNT\Debug\Netlogon.log" -Destination "$destinationPath\$computerName-Netlogon.log"
  else {
    "Could not find Netlogon.log for $computerName" | Out-File -FilePath "$destinationPath\errors.log" -Append

Finally, here are functions to separate the entries I want into different files – separate from the function to gather the NetLogon.log files because it does NOT need to be run as someone with access to your DCs’ c:\Windows\Debug directories…

function Test-NetLogonEntryBadSubnet {
  if ($_ -like "*NO_CLIENT_SITE*") {

function Test-NetLogonEntryBadLogon {
  if ($_ -like "*\[LOGON\]*0xC000006A*" -or $_ -like "*\[LOGON\]*0xC0000234*") {

Function Test-NonTransitiveLogon {
Param($PcNamePrefix = "P0")
  if (($_ -like "*\[LOGON\]*$PcNamePrefix*0x0*") -and ($_ -notlike "*transit*")") {

function Get-NetLogonBadLogonOrSubnet {
  if ($_ -like "*NO_CLIENT_SITE*" -or $_ -like "*\[LOGON\]*0xC000006A*" -or $_ -like "*\[LOGON\]*0xC0000234*") {

function Write-NetlogonExtracts {
, $computerName
, $sourceFile="$directory\$computerName-netlogon.log"
, $targetBadSubnetFile="$directory\$computerName-BadSubnets.txt"
, $targetBadLogonFile="$directory\$computerName-BadLogons.txt"
, $targetDirectLogonFile="$directory\$computerName-DirectLogons.txt"
, $PcNamePrefix = "P0"
# Faster to only filter for one match at a time. Not sure why.
  Get-Content $sourceFile | Test-NetLogonEntryBadSubnet | Out-File -FilePath $targetBadSubnetFile
  Get-Content $sourceFile | Test-NetLogonEntryBadLogon | Out-File -FilePath $targetBadLogonFile
  Get-Content $sourceFile | Test-NonTransitiveLogon -PcNamePrefix $PcNamePrefix | Out-File -FilePath $targetDirectLogonFile

More on parsing the resulting BadSubnets and BadLogons files later… maybe.


3 thoughts on “NetLogon.log: Control what goes in, and get what you want out

    • Hello,
      I added a $Global:TDStamp = (Get-Date).ToString(‘yyyy-MM-dd-hh-mm’) so that we could run multiple times during the day without overwriting the previous collections. Thought I would share. Also, this resolved an issue we were seeing when the time would change the script would ‘lose’ the file that it was writing too and through an error.

      #Create a Global TimeStamp to tag the logs with so data can be collected multiple times without overwriting previous collections.
      $Global:TDStamp = (Get-Date).ToString(‘yyyy-MM-dd_hh-mm’)

      function Get-NetLogonLog {
      if (-not (Test-Path $destinationPath) ) {
      New-Item -Path $destinationPath -ItemType Directory
      if (Test-Path “\\$computerName\c$\WINDOWS\Debug\Netlogon.log”){
      Copy-Item -Path “\\$computerName\c$\WINDOWS\Debug\Netlogon.log” -Destination “$destinationPath\$computerName-Netlogon_$($Global:TDStamp).log”
      elseif (Test-Path “\\$computerName\c$\WINNT\Debug\Netlogon.log”) {
      Copy-Item -Path “\\$computerName\c$\WINNT\Debug\Netlogon.log” -Destination “$destinationPath\$computerName-Netlogon_$($Global:TDStamp).log”
      else {
      “Could not find Netlogon.log for $computerName” | Out-File -FilePath “$destinationPath\errors_$($Global:TDStamp).log” -Append

      Liked by 1 person

Write your own memo:

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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