That million dollar migration question. Who is talking to my Domain Controllers and what are they saying?

These questions are critical when considering a logical Active Directory change to mitigate against service outages. It is inevitable that even after ensuring all LDAP binds are made to the domain DNS name, there will be static Distinguished Names utilised which need to be understood.

This article will guide an Engineer through the steps required to enable LDAP logging and store the events in an easy to digest format.

I came across a very good article written by

Firstly enable Field Engineering debug logging in the registry:-

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostic\15 Field Engineering
Value = 5

1

If you open the Directory Services log you will now see event ID 1644 posted:-

2

You can then run the following PowerShell to write any unique events to a log for analysis.

Column headers are

  • Event Time
  • User Name
  • Root DSE / LDAP Query Search Root
  • LDAP Query
ldap.result

If you would like to export the data into excel. Do so as a text file with a # seperator.

4 5

The PowerShell is below.

# Extract and store useful LDAP queries.
#
# Modification History:-
# 19/04/2016 - Victor Meyer (victor.meyer@esebenza.com)
 
# Set your logfile here
[string]$LogFile = 'C:\LDAP.LOG'
# Function to translate a SID to username
function Translate-Username
{
    param($Event)
	end
    {
        # Get Username
        If($Event.UserId -ne $null)
            {
                $objSID = New-Object System.Security.Principal.SecurityIdentifier($Event.UserId)
                $objUser = $objSID.Translate([System.Security.Principal.NTAccount])
                return $objUser.Value
            }
        else
            {
                return 'Missing'
            }
    }
}
# Simple logger with roll over capability.
Function Write-Event
{
	PARAM([string]$LogMsg, [string]$LogFile)
	END
	{
		# check the size of the current log file.
		if ((Get-Item $LogFile).length -gt 10240kb) 
			{ 
				$NewLogFile = $true 
			} 
		else 
			{ 
                $NewLogFile = $false 
			}
 
		# Check whether a new log should be created or existing log appended.
		If($NewLogFile -eq $true)
			{
				# Test Path [Assume the executing account can make a new logpath]
				if((Test-Path $LogFile) -eq $true)
					{
 
						# Check and delete the previous OLD file
						$LogFileOld = $LogFile.Replace("LOG","OLD")
						if((Test-Path $LogFileOld) -eq $true)
							{
								Remove-Item $LogFileOld -force
							}
						else
							{
								# Rename the old log file
								Rename-Item $LogFile $LogFileOld
							}
 
						# Write the Event Message
						$Date = Get-Date
						Add-Content $LogFile $LogMsg
					}
				else
					{
						# Create a new log file
						New-Item $LogFile -type file -force
 
						# Write the Event Message
						$Date = Get-Date
						Add-Content $LogFile $LogMsg	
					}
			}
		else
			{
				# Write the Event Message
				$Date = Get-Date
				Add-Content $LogFile $LogMsg							
			}
	}
}
# Load all the 1644 Events and store if required.
$Events = Get-WinEvent -FilterHashTable @{Logname='Directory Service';Id=1644}
ForEach($Event in $Events) 
    {
 
 
        # Store relevant properties and Values
        $Date = $Event.TimeCreated
        # Translate the SID to a username
        $User = Translate-Username -Event $Event 
        $RootDSE = $Event.Properties[0].value
        $LdapQuery = ($Event.Properties[1].value).Replace(" ","")
        $LogMsg = "$Date#$User#$RootDSE#$LdapQuery"
        # Here I have filtered out all the LDAP search root's that won't
        # be relevant for a logical OU change.
        if(
            ($RootDSE -ne "RootDSE") `
            -and ($RootDSE -notlike "*CN=Configuration,DC=lab,DC=local") `
            -and ($RootDSE -notlike "*DC=DomainDnsZones,DC=lab,DC=local") `
            -and ($RootDSE -notlike "*DC=ForestDnsZones,DC=lab,DC=local") `
            -and ($RootDSE -ne "DC=lab,DC=local") `
            -and ($User -ne "NT AUTHORITY\SYSTEM") `
            -and ($User -ne "NT AUTHORITY\ANONYMOUS LOGON") `
            -and ($User -ne "LAB\APP-1$")
            )
            {
                # If the combination of date user and root dse do not match what is in the log
                # Create an entry. The log will roll-over at 10 MB
                If((Select-String -Path $LogFile -SimpleMatch "$Date#$User#$RootDSE") -eq $null)
                    {
                        Write-Event -LogMsg $LogMsg -LogFile $LogFile
                    }
 
            }
    }