通过IP地址选择域控制器C#

Choose domain controller by IP address C#

下面是在AD中创建用户的简单代码。该代码是 DC 非特定的。它不关心在哪个 DC 上创建它,它将使用服务器连接到的 windows 默认值。

 using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain, path, ContextOptions.Negotiate, ManagementUsername, ManagementPassword))
                {
                    try
                    {
                        using (UserPrincipal up = new UserPrincipal(pc, username, password, true))
                        {
                            up.GivenName = firstName; up.Surname = lastName; up.DisplayName = firstName + " " + lastName; up.UserPrincipalName = username + "@" + Domain; up.Save();
                        }
                    }
                    catch (PasswordException) { return null; }
                }

问题是新帐户的复制时间(通常域有 15 分钟)。当某人请求在连接到与服务器不同的 DC 的工作站上使用它时,尝试实现按需创建帐户时,这不起作用。他们最终不得不坐在工作站前长达 15 分钟无法登录。

问题: 有没有办法根据客户端 IP 地址连接到 DC 以在该 DC 上创建它?或者有没有办法在所有 DC 上创建帐户并让复制正常进行?或者强制帐户以编程方式复制(基于通过 SO 进行搜索,我猜不是)。

            Forest adForest = Forest.GetCurrentForest();
            ActiveDirectorySite[] sites = new ActiveDirectorySite[adForest.Sites.Count];
            adForest.Sites.CopyTo(sites, 0);
            List<ActiveDirectorySubnet> subnets = new List<ActiveDirectorySubnet>();
            sites.ToList().ForEach(x =>
            {
                ActiveDirectorySubnet[] subnetTemp = new ActiveDirectorySubnet[x.Subnets.Count];
                x.Subnets.CopyTo(subnetTemp, 0);
                subnets.AddRange(subnetTemp);
            });
            IPAddress address = IPAddress.Parse("IPAddress to look up closest DC");
            var currentSubnet = subnets.Where(x => address.IsInRange(x.Name));
            var location = currentSubnet.First().Site.Name;

            DomainController dc = DomainController.FindOne(new DirectoryContext(DirectoryContextType.Domain, Domain), location);

这会为您提供与拓扑中最接近指定 IP 地址的站点和域关联的 DC。 然后将 DC IP 地址传递给主体上下文。

              using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, dc.IPAddress, path, ContextOptions.Negotiate, ManagementUsername, ManagementPassword))
                {
                    try
                    {
                        using (UserPrincipal up = new UserPrincipal(pc, username, password, true))
                        {
                            up.GivenName = firstName; up.Surname = lastName; up.DisplayName = firstName + " " + lastName; up.UserPrincipalName = username + "@" + Domain; up.Save();
                        }
                    }
                    catch (PasswordException) { return null; }
                }

并创建一个用户。

注意:IPAddress 函数是通过 github 上的 NetTools IPAddressRange class 及其以下自定义扩展完成的。

/// <summary>
/// All extensions for IPAddress type
/// </summary>
public static class IPAddressExtension
{
    /// <summary>
    /// Determine whether this IP address is part of the range/subnet
    /// </summary>
    /// <param name="range">A range of IPAddresses</param>
    /// <returns></returns>
    public static bool IsInRange(this IPAddress thisIP, IPAddressRange range)
    {
        return range.Contains(thisIP);
    }

    /// <summary>
    /// Determine whether this IP address is part of the range/subnet
    /// </summary>
    /// <param name="range">Can be specified in CIDR/UNI (ex: 192.168.10.0/24) </param>
    /// <returns></returns>
    public static bool IsInRange(this IPAddress thisIP, string rangeIP)
    {
        IPAddressRange range = IPAddressRange.Parse(rangeIP);
        return range.Contains(thisIP);
    }

    /// <summary>
    /// Determine whether this IP address is part of the range/subnet
    /// </summary>
    /// <param name="ipBegin">Beginning IP address of range</param>
    /// <param name="ipEnd">Ending IP address of range</param>
    /// <returns></returns>
    public static bool IsInRange(this IPAddress thisIP, IPAddress ipBegin, IPAddress ipEnd)
    {
        IPAddressRange range = new IPAddressRange(ipBegin, ipEnd);
        return range.Contains(thisIP);
    }
}