【问题标题】:Query user data from a specific AD DC从特定的 AD DC 查询用户数据
【发布时间】:2015-05-19 07:33:30
【问题描述】:

我想在我们的 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 的信息没有同步。 我知道最合理的措施是审查导致这种不正确同步现象的原因,但是在我目前的状态下,这将需要很长时间并且可能在没有任何发现的情况下结束...... 提前感谢任何建设性的回应/评论!

【问题讨论】:

    标签: c# active-directory domaincontroller


    【解决方案1】:

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

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

    相反,受this answer 的启发,我发现为了找到具有给定 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;
    }
    

    【讨论】:

      【解决方案2】:

      编辑:重新阅读您的问题后,我意识到问题实际上是什么。您认为您有复制问题,因为用户的 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();
      }
      

      它不会显示从未登录过的人。如果你需要,你可能会想办法。

      【讨论】:

      • 感谢它对我有用!我希望我能实现其余的 ;-) 再次感谢您帮助我!
      • 就我而言,以这种方式生成的所有日期都早于用户最近的 Windows 登录时间。这是预期的吗?
      • 找出答案:有点令人困惑的是,LastLogon 指的是LastLogonTimeStamp 属性而不是LastLogon。据我所知,选择后者的唯一方法是降低一层并通过 COM 处理 LDAP。特别是,由于 LastLogonTimeStamp 是按设计复制的,因此为每个域控制器探测它与只为其中一个域控制器探测它的效果相同。
      • 让我将该解决方案添加为自己的答案以供参考。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-26
      • 1970-01-01
      • 1970-01-01
      • 2019-07-12
      相关资源
      最近更新 更多