Question

I am trying to retrieve a list of Computer Names and the date they were last logged onto from Active Directory and return them in a datatable. Getting the names is easy enough but when I try to add the "lastLogon" or "lastLogonTimestamp" like shown below, the only values I get for the lastLogonTimestamp is "System._ComObject"

public DataTable GetListOfComputers(string domainName)
{
  DirectoryEntry entry = new DirectoryEntry("LDAP://DC=" + domainName + ",DC=com");
  DirectorySearcher search = new DirectorySearcher(entry);
  string query = "(objectclass=computer)";
  search.Filter = query;

  search.PropertiesToLoad.Add("name");
  search.PropertiesToLoad.Add("lastLogonTimestamp");

  SearchResultCollection mySearchResultColl = search.FindAll();

  DataTable results = new DataTable();
  results.Columns.Add("name");
  results.Columns.Add("lastLogonTimestamp");

  foreach (SearchResult sr in mySearchResultColl)
  {
    DataRow dr = results.NewRow();
    DirectoryEntry de = sr.GetDirectoryEntry();
    dr["name"] = de.Properties["Name"].Value;
    dr["lastLogonTimestamp"] = de.Properties["lastLogonTimestamp"].Value;
    results.Rows.Add(dr);
    de.Close();
  }

  return results;
}

If I query AD using a tool like LDP I can see that the property exists and is populated with data. How can I get at this info?

Was it helpful?

Solution

It'd be easier to use the ComputerPrincipal class and a PrincipalSearcher from System.DirectoryServices.AccountManagement.

PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName);
PrincipalSearcher ps = new PrincipalSearcher(new ComputerPrincipal(pc));
PrincipalSearchResult<Principal> psr = ps.FindAll();
foreach (ComputerPrincipal cp in psr)
{
    DataRow dr = results.NewRow();
    dr["name"] = cp.Name;
    dr["lastLogonTimestamp"] = cp.LastLogon;    
    results.Rows.Add(dr);
}

OTHER TIPS

**The way to treat the property 'lastLogonTimestamp' retrieved from a DirectoryEntry is to convert it to IADSLargeInteger

from: http://www.dotnet247.com/247reference/msgs/31/159934.aspx**

The __ComObject returned for these types is IADsLargeInteger for the numeric values, and IADsSecurityDescriptor for SecurityDescriptors.

You can include a reference on the COM tab to Active DS Type Lib and get the definition for these interfaces or manually define them. Here is a sample:

using System;
using System.DirectoryServices;
using System.Runtime.InteropServices;

//This is the managed definition of this interface also found in
ActiveDs.tlb
[ComImport]
[Guid("9068270B-0939-11D1-8BE1-00C04FD8D503")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IADsLargeInteger
{
    [DispId(0x00000002)]
    int HighPart{get; set;}
    [DispId(0x00000003)]
    int LowPart{get; set;}
}

class Class1
{
    [STAThread]
    static void Main(string[] args)
    {
        DirectoryEntry entry = new
DirectoryEntry("LDAP://cn=user,cn=users,dc=domain,dc=com");
        if(entry.Properties.Contains("lastLogon"))
        {
            IADsLargeInteger li =
(IADsLargeInteger)entry.Properties["lastLogon"][0];    
            long date = (long)li.HighPart << 32 | (uint)li.LowPart;
            DateTime time = DateTime.FromFileTime(date);
            Console.WriteLine("Last logged on at: {0}", time);
        }
    }

}

David Stucki Microsoft Developer Support

Try using IADsLargeInteger (Source)

DirectoryEntry user = DirectoryEntry("LDAP://" + strDN);
if (user.Properties.Contains("lastlogontimestamp"))
{
  // lastlogontimestamp is a IADsLargeInteger
  IADsLargeInteger li = (IADsLargeInteger) 
  user.Properties["lastlogontimestamp"][0];
  long lastlogonts = 
      (long)li.HighPart << 32 | (uint)li.LowPart;
  user.Close();
  return DateTime.FromFileTime(lastlogonts);
}

A simple answer to the original question is to access the property on your search result:

sr.Properties["lastLogonTimestamp"][0].ToString()

DateTime.FromFileTimeUTC(long.Parse(sr.Properties["lastLogonTimestamp"][0].ToString())) to obtain a datetime value

I'm having a similar issue, I can access the lastLogonTimestamp property in the SearchResult and obtain a value in the indexed result but after using SearchResult.GetDirectoryEntry() I am not able to access a valid result for the lastLogonTimestamp property on the DirectoryEntry.

Has anyone else run into this issue with the DirectoryEntry returned from SearchResult.GetDirectoryEntry() as it relates to access to the lastLogonTimestamp property?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top