0

我想在我们的 AD 中查询一些用户属性,但在 C# 中的特定 DC 上。我们有几十个 DC,我怀疑它们之间存在一些复制问题。我想清理未使用的帐户,我想使用最后一次登录时间属性,我想在所有 DC 上一次次查询这个(我知道这有点像暴力破解,但是我不打算经常做这样的事情)所以我可以查看最新的值是否是最新的。我有查询所有 DC 的代码:

            Domain TestDomain = Domain.GetCurrentDomain();
            Console.WriteLine("Number of found DCs in the domain {0}", TestDomain.DomainControllers.Count);
            foreach (DomainController dc in TestDomain.DomainControllers)
            {
                Console.WriteLine("Name: " + dc.Name);
                ///DO STUFF
            }

而且我还找到了构建可以从 AD 查询用户的代码的帮助:

    PrincipalContext context = new PrincipalContext(ContextType.Domain, "test.domain.com");
            string userName = "testusername";
            UserPrincipal user = UserPrincipal.FindByIdentity(context, userName);
            Console.WriteLine(user.LastLogon.Value.ToString());                
            Console.ReadKey();

在这里我卡住了。现在我想从所有 DC 获取用户的最后登录时间戳。在过去,我已经意外删除了似乎长时间未使用的帐户(仅检查一个 DC),结果发现用户每天都在使用它,因此来自 DC 的信息没有同步。我知道最合理的行动是审查导致这种不正确同步现象的原因,但是在我目前的状态下,这将需要很长时间并且可能在没有任何发现的情况下结束......提前感谢任何建设性的回应/评论!

4

2 回答 2

2

虽然接受的答案是朝着正确方向迈出的一步,但我发现它最终不会产生预期的结果:正如答案中所暗示的,“lastLogon”不会在控制器之间复制,而属性“lastLogonTimeStamp”会被复制(但它另一方面,不能保证错误超过 14 天,参见这个答案)。

现在,相当令人困惑的是,它UserPrincipal.LastLogon不是指未复制但精确的“lastLogon”,而是指复制但不精确的“lastLogonTimeStamp”,我发现通过在接受的答案中运行代码,所有生成DateTime的 s 都是相等且错误的。

相反,受这个答案的启发,我发现为了找到具有给定 sAMAccountName 的用户的最新登录日期(您可以轻松地扩展它以搜索所有用户),我必须执行以下操作:

public DateTime? FindLatestLogonDate(string username)
{
    var logons = new List<DateTime>();
    DomainControllerCollection domains = Domain.GetCurrentDomain().DomainControllers;
    foreach (DomainController controller in domains)
    {
        using (var directoryEntry = new DirectoryEntry($"LDAP://{controller.Name}"))
        {
            using (var searcher = new DirectorySearcher(directoryEntry))
            {
                searcher.PageSize = 1000;
                searcher.Filter = $"((sAMAccountName={username}))";
                searcher.PropertiesToLoad.AddRange(new[] { "lastLogon" });
                foreach (SearchResult searchResult in searcher.FindAll())
                {
                    if (!searchResult.Properties.Contains("lastLogon")) continue;
                    var lastLogOn = DateTime.FromFileTime((long)searchResult.Properties["lastLogon"][0]);
                    logons.Add(lastLogOn);
                }
            }
        }
    }
    return logons.Any() ? logons.Max() : (DateTime?)null;
}
于 2018-08-04T12:15:43.563 回答
0

编辑:重新阅读您的问题后,我意识到问题实际上是什么。您认为您有复制问题,因为用户的 Last Logon 属性在所有域控制器上都不匹配?这是设计使然!该属性是特定于域控制器的,并且不被复制。要检查用户的真实最后登录时间,您必须始终查询每个域控制器以找到最新时间!

你快到了,试试这个:

public static List<UserPrincipal> GetInactiveUsers(TimeSpan inactivityTime)
{
    List<UserPrincipal> users = new List<UserPrincipal>();

    using (Domain domain = Domain.GetCurrentDomain())
    {
        foreach (DomainController domainController in domain.DomainControllers)
        {
            using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domainController.Name))
            using (UserPrincipal userPrincipal = new UserPrincipal(context))
            using (PrincipalSearcher searcher = new PrincipalSearcher(userPrincipal))
            using (PrincipalSearchResult<Principal> results = searcher.FindAll())
            {
                users.AddRange(results.OfType<UserPrincipal>().Where(u => u.LastLogon.HasValue));
            }
        }
    }

    return users.Where(u1 => !users.Any(u2 => u2.UserPrincipalName == u1.UserPrincipalName && u2.LastLogon > u1.LastLogon))
        .Where(u => (DateTime.Now - u.LastLogon) >= inactivityTime).ToList();
}

它不会显示从未登录过的人。如果您需要,您可能会弄清楚。

于 2015-05-19T15:15:11.477 回答