如何使用LDAP和C#获取域控制器信息、状态及复制状态?
使用LDAP和C#远程获取域控制器信息、运行状态及复制状态
我希望通过LDAP和C#远程获取域控制器的相关信息、运行状态及复制状态(比如在PC1上运行代码,获取PC2的数据)。我知道用WMI可以执行以下查询实现该需求:
SELECT * FROM MSAD_DomainController then SELECT * FROM MSAD_ReplCursor where SourceDsaDN like '%{domainControllerName}%' then SELECT * FROM MSAD_ReplNeighbor where NamingContextDN like '{NamingContextDN->From above query}'
请问用LDAP时,该如何实现类似WMI查询的功能?我目前用以下C#代码查询域控制器详情:
using System.DirectoryServices; using System.DirectoryServices.ActiveDirectory; class Program { static void Main() { string domainname = {Domain}; string username = {User}; string password = {Pass}; try { // Using DirectoryEntry for LDAP operations string ipAddress = {IP}; string ldapPath = $"LDAP://{ipAddress}:389/DC={domainname},DC=com"; using (DirectoryEntry entry = new DirectoryEntry(ldapPath, username, password, AuthenticationTypes.Secure)) { using (DirectorySearcher searcher = new DirectorySearcher(entry)) { searcher.Filter = "(objectClass=*)"; searcher.SearchScope = SearchScope.Subtree; SearchResultCollection results = searcher.FindAll(); if (results.Count == 0) { Console.WriteLine("No objects found."); } else { foreach (SearchResult result in results) { Console.WriteLine("Object Information:"); if (result.Properties["objectClass"].Count > 0) { Console.Write($"Object Class: "); foreach (var value in result.Properties["objectClass"]) { Console.Write($"{value}, "); // Print each value } } foreach (string propertyName in result.Properties.PropertyNames) { var propertyValues = result.Properties[propertyName]; if (propertyValues.Count > 0) { Console.Write($"{propertyName}: "); foreach (var value in propertyValues) { Console.Write($"{value}, "); // Print each value } Console.WriteLine(); // New line after values } else { Console.WriteLine($"{propertyName}: Not Available or Empty"); } } Console.WriteLine("---------------------------------------------------"); } } } } } catch (ActiveDirectoryObjectNotFoundException ex) { Console.WriteLine($"Error: {ex.Message} - Check domain name and connectivity."); } catch (ActiveDirectoryOperationException ex) { Console.WriteLine($"AD Operation Error: {ex.Message}"); } catch (DirectoryServicesCOMException ex) { Console.WriteLine($"Directory Services Error: {ex.Message}"); } catch (Exception ex) { Console.WriteLine($"Unexpected Error: {ex.Message}"); } } }
解决方案
LDAP可通过查询AD中特定对象类和属性,实现与WMI对应的功能,以下是具体实现方式及优化后的C#代码:
1. 对应MSAD_DomainController:获取域控制器基础信息
域控制器在AD中以nTDSDSA对象类存在,存储路径为CN=Servers,CN={站点名},CN=Sites,CN=Configuration,{域根DN},可直接通过(objectClass=nTDSDSA)过滤查询。
核心属性:
dNSHostName:域控制器FQDNserverReference:关联的服务器对象DNwhenCreated:域控制器创建时间options:域控制器配置选项
2. 对应MSAD_ReplCursor:获取复制游标信息
复制游标数据存储在域控制器nTDSDSA对象的replPropertyMetaData属性中,也可通过msDS-ReplAttributeMetaData(属性级复制元数据)、msDS-ReplValueMetaData(值级复制元数据)获取更详细的复制状态。
3. 对应MSAD_ReplNeighbor:获取复制邻居信息
复制邻居信息对应AD中的replNeighbor对象,可通过域控制器nTDSDSA对象的replNeighbors属性查询,也可直接访问CN=NTDS Settings,CN={DC名},CN=Servers,CN={站点名},CN=Sites,CN=Configuration,{域根DN}对象的msDS-ReplNeighbors属性。
完整C#代码示例
以下代码实现远程查询指定域控制器的三类目标数据:
using System; using System.DirectoryServices; class DomainControllerLdapTool { static void Main() { string domainRoot = "DC=contoso,DC=com"; string targetDcIp = "192.168.1.10"; string authUser = "contoso\\domain_reader"; string authPass = "YourSecurePassword"; try { // 1. 查询域控制器基础信息 Console.WriteLine("=== 域控制器基础信息 ==="); string configPartition = $"CN=Configuration,{domainRoot}"; using (var configEntry = new DirectoryEntry($"LDAP://{targetDcIp}:389/{configPartition}", authUser, authPass, AuthenticationTypes.Secure)) { var dcSearcher = new DirectorySearcher(configEntry) { Filter = "(objectClass=nTDSDSA)", SearchScope = SearchScope.Subtree, PropertiesToLoad = { "dNSHostName", "serverReference", "whenCreated", "options" } }; var dcResult = dcSearcher.FindOne(); if (dcResult != null) { Console.WriteLine($"FQDN: {dcResult.Properties["dNSHostName"][0]}"); Console.WriteLine($"服务器DN: {dcResult.Properties["serverReference"][0]}"); Console.WriteLine($"创建时间: {dcResult.Properties["whenCreated"][0]}"); Console.WriteLine($"配置选项: {dcResult.Properties["options"][0]}"); } } // 2. 查询复制游标信息(以域分区元数据为例) Console.WriteLine("\n=== 复制游标信息 ==="); using (var domainEntry = new DirectoryEntry($"LDAP://{targetDcIp}:389/{domainRoot}", authUser, authPass, AuthenticationTypes.Secure)) { var metaSearcher = new DirectorySearcher(domainEntry) { Filter = "(objectClass=domain)", PropertiesToLoad = { "msDS-ReplAttributeMetaData" } }; var metaResult = metaSearcher.FindOne(); if (metaResult != null && metaResult.Properties["msDS-ReplAttributeMetaData"].Count > 0) { foreach (byte[] metaData in metaResult.Properties["msDS-ReplAttributeMetaData"]) { // 二进制元数据需按AD规范解析,此处简化输出 Console.WriteLine($"元数据片段: {BitConverter.ToString(metaData).Substring(0, 60)}..."); } } } // 3. 查询复制邻居信息 Console.WriteLine("\n=== 复制邻居信息 ==="); using (var configEntry = new DirectoryEntry($"LDAP://{targetDcIp}:389/{configPartition}", authUser, authPass, AuthenticationTypes.Secure)) { // 先定位目标DC的NTDS Settings对象 var ntdsSearcher = new DirectorySearcher(configEntry) { Filter = "(&(objectClass=nTDSDSA)(dNSHostName=dc01.contoso.com))", // 替换为目标DC的FQDN PropertiesToLoad = { "replNeighbors" } }; var ntdsResult = ntdsSearcher.FindOne(); if (ntdsResult != null && ntdsResult.Properties["replNeighbors"].Count > 0) { foreach (string neighborDn in ntdsResult.Properties["replNeighbors"]) { Console.WriteLine($"\n邻居DN: {neighborDn}"); using (var neighborEntry = new DirectoryEntry($"LDAP://{targetDcIp}:389/{neighborDn}", authUser, authPass, AuthenticationTypes.Secure)) { Console.WriteLine($"状态: {neighborEntry.Properties["replState"]?[0] ?? "未知"}"); Console.WriteLine($"上次成功复制: {neighborEntry.Properties["lastSuccessfulSync"]?[0] ?? "无记录"}"); } } } } } catch (DirectoryServicesCOMException ex) { Console.WriteLine($"LDAP错误: {ex.Message}, 错误码: {ex.ErrorCode}"); } catch (Exception ex) { Console.WriteLine($"异常: {ex.Message}"); } } }
注意事项
- 确保运行代码的设备能访问目标域控制器的LDAP端口(默认389,SSL用636)
- 所用账号需具备读取AD配置分区和域分区的权限
- 复制元数据为二进制格式,需参照AD官方文档解析具体字段
内容的提问来源于stack exchange,提问作者NeoGenesis521
相关产品推荐
相关产品推荐

