3

How can I get a list of users from active directory?

Please see the page above. It answered most of my questions, but I get a problem when I try to get last logon time for a computer. Sorry if there was some way to comment on that page instead of making a whole new question because I didn't find such an option.

using (var context = new PrincipalContext(ContextType.Domain, "cat.pcsb.org"))
        {
            using (var searcher = new PrincipalSearcher(new ComputerPrincipal(context)))
            {
                foreach (var result in searcher.FindAll())
                {
                    DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
                    Console.WriteLine("Name: " + de.Properties["name"].Value);
                    Console.WriteLine("Last Logon Time: " + de.Properties["lastLogon"].Value);
                    Console.WriteLine();
                }
            }
        }
        Console.ReadLine();

I replaced UserPrincipal with ComputerPrincipal. Name and some other properties work fine, but logon doesn't. I've tried doing different things like casting it to DateTime (the cast failed) but nothing worked. The above just results in System.__ComObject. So what can I do to get it to get last logon time correctly?

Community
  • 1
  • 1
Baga Jr.
  • 153
  • 3
  • 6
  • 12

2 Answers2

8

Why aren't you just using the the LastLogon property returned by ComputerPrincipal? (ComputerPrincipal is a AuthenicatablePrincipal)

using (var context = new PrincipalContext(ContextType.Domain, "cat.pcsb.org"))
{
    using (var searcher = new PrincipalSearcher(new ComputerPrincipal(context)))
    {
        foreach (var result in searcher.FindAll())
        {
            var auth = result as AuthenticablePrincipal;
            if(auth != null)
            {
                Console.WriteLine("Name: " + auth.Name);
                Console.WriteLine("Last Logon Time: " + auth.LastLogon);
                Console.WriteLine();
            }
        }
    }
}
Console.ReadLine();

Note that LastLogon is not a replicated property, so if you have more than one domain controller you need to query each controller and find out who gives the most recent result.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • Thanks, I tried that by doing "as ComputerPrincipal" (which works too) but it didn't work because I probably forgot to check for null so I went back to the example that I gave with replicated properties even though logon apparently isn't one... I'm going to go bang my head against the wall now. – Baga Jr. Oct 21 '13 at 15:04
  • I mentioned that ComputerPrincipal works but is AuthenticablePrincipal better for this in any way? Also, I don't see any property about logon other than time, so is there some way I can get more info about the last logon, like which user it was? – Baga Jr. Oct 21 '13 at 15:11
  • @BagaJr. No I just used AuthenticablePrincipal as the same code would work for both users and computers, however "LastLogon" I think is the last time the computer itself authenticated itself against the network, not the last time a user logged on the computer. – Scott Chamberlain Oct 21 '13 at 15:13
  • Include this: using System.DirectoryServices.AccountManagement; – Jeff Jan 13 '21 at 23:26
  • This is not corresponding to LastLongon attribute but LastLogonTimestamp. So it's not working – Safirion Sep 12 '22 at 12:58
4

You need to iterate through all domain controllers and find the lastest logon time.

The below code finds last logon time for a user.

public DateTime findlastlogon(string userName)

    {
        DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, "domainName");
        DateTime latestLogon = DateTime.MinValue;
        DomainControllerCollection dcc = DomainController.FindAll(context);
        Parallel.ForEach(dcc.Cast<object>(), dc1 =>
                {


                    DirectorySearcher ds;
                    DomainController dc = (DomainController)dc1;
                    using (ds = dc.GetDirectorySearcher())
                    {
                        try
                        {
                            ds.Filter = String.Format(
                              "(sAMAccountName={0})",
                              userName
                              );
                            ds.PropertiesToLoad.Add("lastLogon");
                            ds.SizeLimit = 1;
                            SearchResult sr = ds.FindOne();

                            if (sr != null)
                            {
                                DateTime lastLogon = DateTime.MinValue;
                                if (sr.Properties.Contains("lastLogon"))
                                {
                                    lastLogon = DateTime.FromFileTime(
                                      (long)sr.Properties["lastLogon"][0]
                                      );
                                }

                                if (DateTime.Compare(lastLogon, latestLogon) > 0)
                                {
                                    latestLogon = lastLogon;
                                    //servername = dc1.Name;
                                }
                            }
                        }
                        catch (Exception)
                        {

                        }                          
                    }
                });
        return latestLogon;
    }

To get last logon time for a computer replace sAMAccountName to Name.

ds.Filter = String.Format( "(Name={0})", userName );

Dalton
  • 1,334
  • 1
  • 11
  • 19
  • It doesn't even enter the foreach loop once. – Baga Jr. Oct 29 '13 at 15:04
  • what is the value of dcc.Count? – Dalton Oct 30 '13 at 05:59
  • Never mind that, it works now. The only problem is that when I log onto a computer, the computer's last logon time and mine are about a minute off. So how can I get the last logon time for a computer as well as the user that logged on at that time? – Baga Jr. Nov 05 '13 at 16:50