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: http://support.microsoft.com/kb/109626
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” http://technet.microsoft.com/en-us/library/cc776964.aspx, 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 { Param( $computerName ,$destinationPath="C:\temp\netlogon" ) 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 { PROCESS { if ($_ -like "*NO_CLIENT_SITE*") { $_ } } } function Test-NetLogonEntryBadLogon { PROCESS { if ($_ -like "*\[LOGON\]*0xC000006A*" -or $_ -like "*\[LOGON\]*0xC0000234*") { $_ } } } Function Test-NonTransitiveLogon { Param($PcNamePrefix = "P0") PROCESS { if (($_ -like "*\[LOGON\]*$PcNamePrefix*0x0*") -and ($_ -notlike "*transit*")") { $_ } } } function Get-NetLogonBadLogonOrSubnet { PROCESS { if ($_ -like "*NO_CLIENT_SITE*" -or $_ -like "*\[LOGON\]*0xC000006A*" -or $_ -like "*\[LOGON\]*0xC0000234*") { $_ } } } function Write-NetlogonExtracts { Param( $directory="c:\temp\netlogon" , $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.
Hello,
Just wanted to say thank you for posting this information and the functions, they are excellent!
Regards,
Brian
LikeLike
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 {
Param(
$computerName
,$destinationPath=”C:\temp\netlogon”
)
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
}
}
LikeLiked by 1 person
Nice! Thanks for sharing!
LikeLike