Wednesday, October 14, 2026

Identify LDAP Applications Using a DC

One of the issues when decommissioning a domain controller is identifying any applications using that specific DC for LDAP authentication. Standard clients will use DNS records to find an alternate DC, but LDAP applications are typically configured with a static IP address or DNS name for authentication.

Identifying LDAP application authentication is difficult because both the applications and standard client authentication use LDAP. There is nothing in the event logs to differentiate them. The best option is to get clients to avoid using the DC for authentication. Then, all remaining traffic is LDAP applications that can be investigated.

There are two potential methods for pushing clients to use other DCs for authentication:

  • Put the DC in it's own site.
  • Change the priority of DNS records for the DC.

Clients prefer to use a domain controller in their own Active Directory site for authentication. If you create a new site specifically for the retiring DC, then clients should avoid it for authentication.

The DNS records that clients use to find DCs for authentication include a priority value. Clients attempt to contact DCs with a lower priority value first. The default priority value on the DNS records is 0 (zero). If you change the priority for the retiring DC, then all other DCs should be preferred and pretty much eliminate client authentication traffic.

You can manually change the priority on DNS records for the retiring DC, but there are quite a few and the DC may eventually change the priority back to 0. Instead set the LdapSrvPriority registry value that the DC will use to register it's own DNS records. The value does not exist by default and you will need to create it in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters.

You can also use GPO setting Priority Set in the domain controller locator DNS SRV Records for the Net Logon Service. If you use a GPO, then you'll need to use security filtering based on the computer object to have it apply only to the DC you want as it will be linked to the Domain Controllers OU.

Whichever method you use, clients might have cached information about sites or DNS records. It will take some time for the cached info to expire. This is not a get it done in 30 minutes activity. 

Reference for LdapSrvPriority value: https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/optimize-dc-location-global-catalog

When I initially looked at this issue, I thought that the registry value DnsAvoidRegisterRecords would filter out clients requests. However, this only prevents the DC from registering DNS records outside of the local site, thus preventing client authentication from non-local sites. As part of DC retirement, we need to discourage/disable client authentication in the local site as well. So, this is not effective.  

Tuesday, August 25, 2026

Fast Event Log Query with FilterXPath

I've been working with Powershell for way too long to have just figured this out. However, here we are...

To query event log information from a remote server, you can use Get-WinEvent. However, I've always found it really slow and not very flexible.

Recently I needed to get events from the Security log related to NTLM v1 authentication and there were about 200,000 events in the security log. The event ID that I needed to evaluate was about half of that. So, I needed to query 100,000 events.

When I used the -FilterHashTable parameter, it took about 10 minutes. That's not a good time. And processing the results also took about 10 minutes.

Many events were not relevant, because I only needed events that referred to NTLM v1 authentication. This reference was in the message and I was doing text processing on the message attribute to find the relevant events.

If you use -FilterXPath, you can refer to items in the message as an attribute and filter based on them. This got my query from 10 minutes down to less than a minute. You can view the attributes available for filtering in the properties of an event in the XML view. What appears as text in the message shows up as specific data names in EventData that you can filter on.

 

 Here is an example of the code:

#Query only events with NTLM V1 (1 min or less per DC)
$comp = "XXXXXXX"
$xpath = "*[System[EventID=4624] and EventData[Data[@Name='LMPackageName']='NTLM V1']]"
$LogonEvents = Get-WinEvent -ComputerName $comp -Credential $cred -FilterXPath $xpath -LogName Security

The filter I used looked for EventID=4624 in the System section of the event. In the EventData portion of the event, it looked for LMPackageName='NTLM v1'. Normally LMPackageName appears in the message portion of the event and it's not filterable. Shown below as Package Name (NTLM only) with a value of -.

So, -FilterXPath is more flexible for filtering which significantly reduces the number of events transferred by Get-WinEvent and provides a huge increase in speed.

 

Audit NTLM v1 on DC

Windows Server 2025 no longer supports NTLM v1 (which shouldn't exist on your network). However, just to be safe before updating domain controllers, we should verify.

The following script queries relevant events from the security log (fast using FilterXPath) and groups them.

If all of the events returned are for ANONYMOUS LOGON then you can ignore them. The logging logic in Windows gives false positives for NTLM v1 with anonymous authentication. When it doesn't see NTLM v2, it logs it as NTLM v1.

More info here: https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/audit-domain-controller-ntlmv1

$cred = Get-Credential

#Query only events with NTLM V1 (1 min or less per DC)
$comp = "XXXXXXX"
$xpath = "*[System[EventID=4624] and EventData[Data[@Name='LMPackageName']='NTLM V1']]"
$LogonEvents = Get-WinEvent -ComputerName $comp -Credential $cred -FilterXPath $xpath -LogName Security

foreach ($event in $LogonEvents) {

    $lines = $event.message -split '\r?\n'
    $AcctLine = $lines | where {$_ -like "*Account Name:*"} 
    $Acct = ($AcctLine[1] -split ":")[1].trim()
    $event | Add-Member -NotePropertyName Account -NotePropertyValue $Acct -force


    $NTLM = $lines | where {$_ -like "*Package Name (NTLM only):*"} 
    $NTLMVersion = ($NTLM -split ":")[1].trim()
    $event | Add-Member -NotePropertyName NTLMVersion -NotePropertyValue $NTLMVersion -force

    $WS = $lines | where {$_ -like "*Workstation Name:*"} 
    $WSName = ($WS -split ":")[1].trim()
    $event | Add-Member -NotePropertyName Workstation -NotePropertyValue $WSName -force

} #end foreach

#Make sure only NTLM v1
$LogonEvents | Group-Object -Property NTLMVersion

#Can ignore ANONYMOUS LOGON
$logonevents | where NTLMVersion -eq "NTLM V1" | Group-Object Account

#In case you care which computers they're coming from
$LogonEvents | Group-Object Workstation

Wednesday, April 22, 2026

Modern Hybrid Agent Install Fails

I've run into this a few times, and since setting this up isn't a common thing anymore, this is my reminder as to a common issue.

When the hybrid agent installs and fails to connect afterwards, it's often due to Extended Protection being enabled in IIS on the Exchange Server.

Quick overview of the fix:

  • Download the ExchangeExtendedProtectionManagement.ps1 script from https://microsoft.github.io/CSS-Exchange/Security/ExchangeExtendedProtectionManagement/
  • Use the script to disable Extended Protection
    .\ExchangeExtendedProtectionManagement.ps1 -DisableExtendedProtection
  • Install the hybrid agent via Hybrid Wizard
  • Enable Extended Protection to support the hybrid agent
    .\ExchangeExtendedProtectionManagement.ps1 -ExchangeServerNames MHServer1, MHServer2 -ExcludeVirtualDirectories "EWSFrontEnd"

Might need to disable again if re-running the hybrid agent after updating certificate.

These instructions are being used for Exchange Server SE. 

Reference links: