我正在尝试获取 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.'
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);
}