如何使用c#远程获取Active Directory信息?

问题描述 投票:0回答:1

我正在尝试获取 Active Directory 信息,例如 AD 复制状态和其他类型的信息。现在,我只关注 AD 复制状态。我用这个代码远程登录电脑。

// P/Invoke for LogonUser
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword,
    int dwLogonType, int dwLogonProvider, out IntPtr phToken);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);

[DllImport("kernel32.dll")]
public static extern int GetLastError();

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int FormatMessage(uint dwFlags,IntPtr lpSource,uint dwMessageId,uint dwLanguageId,StringBuilder lpBuffer,uint nSize,IntPtr Arguments);

private const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
private const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
private const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
IntPtr tokenHandle;

public ADClass()
{
    IntPtr tokenHandle = IntPtr.Zero;
    _logonSuccess = LogonUser(user, domain, pass, 9, 3, out tokenHandle);
}

public void DomainControllerStatus(string machinenames) 
{
    try
    {
        if(_logonSuccess)
        {
            using (WindowsIdentity identity = new WindowsIdentity(tokenHandle))
            {
                // Now, you're running under the context of the impersonated user.
                WindowsIdentity.RunImpersonated(identity.AccessToken, () =>
                {
                    try
                    {
                        // Approach 1: 
                        string repadminPath = $@"\\{machine}\C$\Windows\System32\repadmin.exe";

                        ProcessStartInfo processInfo = new ProcessStartInfo(repadminPath, "/replsummary")
                        {
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            UseShellExecute = false,
                            CreateNoWindow = true
                        };

                        Process process = Process.Start(processInfo);
                        string output = process.StandardOutput.ReadToEnd();
                        process.WaitForExit();
                        
                        Console.WriteLine($"Status: {output}"); // Output is always ""
                        
                        // Approach 2: 
                        Domain domain = Domain.GetCurrentDomain(); // Comes out with this message: System.DirectoryServices.ActiveDirectory.ActiveDirectoryOperationException: Current security context is not 
                        // associated with an Active Directory domain or forest.

                        // Loop through each domain controller in the domain
                        foreach (DomainController dc in domain.DomainControllers)
                        {
                            StringBuilder output = new StringBuilder();
                            Console.WriteLine($"Checking replication for Domain Controller: {dc.Name}");

                            _IsConnected = true;

                            // Get replication neighbors (replication partners)
                            foreach (ReplicationNeighbor neighbor in dc.GetAllReplicationNeighbors())
                            {
                                output.Append($"Neighbor: {neighbor.SourceServer};");
                                output.Append($"Last Attempt: {neighbor.LastAttemptedSync};");
                                output.Append($"Last Success: {neighbor.LastSuccessfulSync};");
                                output.Append($"Consecutive Failure Count: {neighbor.ConsecutiveFailureCount};");

                                Console.WriteLine($"AD Replication => {output.ToString()}");
                            }
                        }
                        
                        // Approach 3:
                        //string ldapPath = $"LDAP://DC={domain},DC=com";  // Adjust the domain accordingly
                        string ldapPath = $"LDAP://{domain}";  // Adjust the domain accordingly

                        using (DirectoryEntry entry = new DirectoryEntry(ldapPath, user, pass))
                        {
                            // Ensure we can connect and authenticate
                            Console.WriteLine("Authenticated with LDAP: " + entry.Name); // Comes out with this message: System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational.

                            // Create a DirectorySearcher to query the domain
                            DirectorySearcher searcher = new DirectorySearcher(entry)
                            {
                                Filter = "(objectClass=domain)"
                            };

                            SearchResult result = searcher.FindOne();

                            if (result != null)
                            {
                                Console.WriteLine("Domain found: " + result.Path);
                            }
                            else
                            {
                                Console.WriteLine("Domain not found or no results.");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Exception Error Message: {ex}");
                    }
                }
            }
        }
        else
        {
            int errorCode = Marshal.GetLastWin32Error();
            string errorMessage = GetErrorMessage(errorCode);
            Console.WriteLine($"LogonUser failed with error code: {errorCode}; Message: {errorMessage}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception Error Message: {ex}");
    }
}

static string GetErrorMessage(int errorCode)
{
    StringBuilder messageBuffer = new StringBuilder(512);
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,IntPtr.Zero,(uint)errorCode,0,messageBuffer,(uint)messageBuffer.Capacity,IntPtr.Zero);

    return messageBuffer.ToString();
}

(我遇到的错误可以在每种方法中作为评论找到)

使用此代码,我可以远程登录到 PC,但是,当涉及到获取有关域控制器的信息(例如 AD 复制状态)时,我没有从输出中获取任何信息。我该如何解决这个问题以及我在功能/方法上犯了哪些错误?

方法3更新

当我修改这部分代码时

string username = $"{domain}\\{user}";

using (DirectoryEntry entry = new DirectoryEntry(ldapPath, username, pass))

我收到此错误:

System.Runtime.InteropServices.COMException: 'The specified domain either does not exist or could not be contacted.'
c# active-directory remote-access domaincontroller
1个回答
0
投票

您可以直接使用 C# 中的 Powershell 脚本。

Get-ADReplicationFailure
似乎就是您要找的。

首先创建一个Runspace,然后添加命令,并执行。

using PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-ADReplicationFailure")
    .AddParameter("Target", "YourDomain")
    .AddParameter("EnumeratingServer", "YourDC");

foreach (PSObject result in ps.Invoke())
{
    Console.WriteLine(result);
}
© www.soinside.com 2019 - 2024. All rights reserved.