在多个域服务器中搜索用户的lastLogon属性

时间:2013-04-02 22:04:43

标签: c# active-directory ldap

首先,如果我没有使用正确的术语,请原谅我。无论我在哪里使用错误的术语,都要纠正我。

目标是以编程方式检索给定用户名的lastLogon日期。

我相信是一片森林;两个AD服务器,如 - adserver01.aa.mycompany.comadserver02.aa.mycompany.com

我使用Microsoft的ADExplorer从第三台计算机连接到这些服务器以检查对象。我在adserver01看到一些用户有上次登录日期,但adserver02没有。例如,lastLogon的值在adserver02中为0x0,而对于某些用户来说,它是adserver01中的有效日期。

到目前为止,我开发的代码是Windows窗体应用程序,如果只涉及一个AD服务器,则可以正常工作。对于lastLogon日期属性,如何检查两个服务器并返回非零值(如果可用)?

        private static string GetLastActivityDate(string UserName)
    {
        string domainAndUserName = String.Format(@"LDAP://aa.mycompany.com/CN={0},OU=CLIENT_PROD,OU=clients.mycompany.com,DC=aa,DC=mycompany,DC=com", UserName);
        string OUAdminUserName = "abc";
        string OUAdminPassword = "xyz";
        AuthenticationTypes at = AuthenticationTypes.Secure;
        DateTime lastActivityDate;
        string returnvalue;
        long lastLogonDateAsLong;


        using (DirectoryEntry entryUser = new DirectoryEntry(domainAndUserName, OUAdminUserName, OUAdminPassword, at))
        using (DirectorySearcher mysearcher = new DirectorySearcher(entryUser))
            try
            {
                using (SearchResultCollection results = mysearcher.FindAll())
                {
                    if (results.Count >= 1)
                    {
                        DirectoryEntry de = results[0].GetDirectoryEntry();
                        lastLogonDateAsLong = GetInt64(de, "lastLogon");
                        try
                        {
                            if (lastLogonDateAsLong != -1)
                            {
                                lastActivityDate = DateTime.FromFileTime(lastLogonDateAsLong);
                                returnvalue = lastActivityDate.ToString();
                            }
                            else
                            {
                                returnvalue = "-Not available-";
                            }
                        }
                        catch (System.ArgumentOutOfRangeException aore)
                        {
                            returnvalue = "Not available";
                        }
                    }
                    else
                    {
                        returnvalue = string.Empty;
                    }
                }
            }
            catch (System.DirectoryServices.DirectoryServicesCOMException dsce)
            {
                returnvalue = "- Not available -";
            }


        return returnvalue;
    }

谢谢。

编辑:

 private static Int64 GetInt64(DirectoryEntry entry, string attr)
    {

        DirectorySearcher ds = new DirectorySearcher(
            entry,
            String.Format("({0}=*)", attr),
            new string[] { attr },
            SearchScope.Base
            );

        SearchResult sr = ds.FindOne();

        if (sr != null)
        {
            if (sr.Properties.Contains(attr))
            {
                return (Int64)sr.Properties[attr][0];
            }
        }
        return -1;
    }

忘记提及,AD模式,结构等在两个服务器中看起来完全相同。

2 个答案:

答案 0 :(得分:3)

查看此帖子 http://www.codeproject.com/Articles/19181/Find-LastLogon-Across-All-Windows-Domain-Controlle

我有同样的问题,但只针对一个域名, 我通过使用以下代码解决了它,但我正在检查所有用户的lastLogin

 public static Dictionary<string, DateTime> UsersLastLogOnDate()
   {
       var lastLogins = new Dictionary<string, DateTime>();
       DomainControllerCollection domains = Domain.GetCurrentDomain().DomainControllers;
       foreach (DomainController controller in domains)
       {
           try
           {
               using (var directoryEntry = new DirectoryEntry(string.Format("LDAP://{0}", controller.Name)))
               {
                   using (var searcher = new DirectorySearcher(directoryEntry))
                   {
                       searcher.PageSize = 1000;
                       searcher.Filter = "(&(objectClass=user)(!objectClass=computer))";
                       searcher.PropertiesToLoad.AddRange(new[] { "distinguishedName", "lastLogon" });
                       foreach (SearchResult searchResult in searcher.FindAll())
                       {
                           if (searchResult.Properties.Contains("lastLogon"))
                           {
                               var lastLogOn = DateTime.FromFileTime((long)searchResult.Properties["lastLogon"][0]);
                               var username = Parser.ParseLdapAttrValue(searchResult.Properties["distinguishedName"][0].ToString());
                               if (lastLogins.ContainsKey(username))
                               {
                                   if (DateTime.Compare(lastLogOn, lastLogins[username]) > 0)
                                   {
                                       lastLogins[username] = lastLogOn;
                                   }
                               }
                               else
                               {
                                   lastLogins.Add(username, lastLogOn);
                               }
                           }
                       }
                   }

               }


           }
           catch (System.Runtime.InteropServices.COMException comException)
           {
               // Domain controller is down or not responding
               Log.DebugFormat("Domain controller {0} is not responding.",controller.Name);
               Log.Error("Error in one of the domain controllers.", comException);
               continue;
           }
       }
       return lastLogins;
   }

在代码之上,您可以使用以下内容获取林中的所有域。

Forest currentForest = Forest.GetCurrentForest();  
DomainCollection domains = currentForest.Domains;  
foreach(Domain domain in domains)  
{  
   // check code above  
}  

答案 1 :(得分:1)

可能有一种更简单的方法?实际上有另一个属性lastLogonTimestamp,我认为它添加了2003域级别,试图在最后一次登录的域中保持单个一致的值。唉,它有一个奇怪的复制时间模式,可能会有两个星期过时。