Casting the ActiveDirectory pwdLastSet property without using ActiveD

Ok. So I am trying to find a way to avoid including ActiveD in my project because I am having trouble getting the DLL in the installer. The only reason it needs to be done is: pwdLastSet as LongInteger.

I found an undocumented alternative. In testing, it is either dead or 429.49673 seconds. I don't know why, does anyone have any ideas? (20/49 people I tested - 429.49673 seconds).

UPDATE . It looks like it happens when the LowPart is negative.


    private static string DateTest() {
        return DateTest(Environment.UserName);
    private static string DateTest(string userName) {
        userName = userName.Trim();
        DateTime hacked, normal;
        using (DirectorySearcher ds = new DirectorySearcher()) {
            ds.SearchScope = SearchScope.Subtree;
            ds.PageSize = 1;
            ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
            ds.Filter = string.Format("(&(objectCategory=user)(sAMAccountName={0}))", userName);

            SearchResult sr = ds.FindOne();
            hacked = DateTime.FromFileTime((long)sr.Properties["pwdLastSet"][0]);

            using (DirectoryEntry user = sr.GetDirectoryEntry()) {
                var value = user.Properties["pwdLastSet"][0] as ActiveDs.LargeInteger;
                var longValue = (((long)value.HighPart) << 32) + (long)value.LowPart;
                normal = DateTime.FromFileTime(longValue);

        return string.Format("{3} - Difference: {0:0.0} seconds. Established Method returns: {1}. Hacked method returns: {2}",
            hacked.Subtract(normal).TotalSeconds, normal, hacked, userName);



  • Active DS Type Library
  • System.DirectoryServices

source to share

2 answers

You will need to translate AD Long Integer this way and you don't need ActiveD anymore:

long pwdLastSet = CovertADSLargeIntegerToInt64(oUser.Properties["pwdLastSet"].Value);

public static Int64 ConvertADSLargeIntegerToInt64(object adsLargeInteger)
  var highPart = (Int32)adsLargeInteger.GetType().InvokeMember("HighPart", System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
  var lowPart  = (Int32)adsLargeInteger.GetType().InvokeMember("LowPart",  System.Reflection.BindingFlags.GetProperty, null, adsLargeInteger, null);
  return highPart * ((Int64)UInt32.MaxValue + 1) + lowPart;




What's wrong with this code? It should work fine:

    SearchResult sr = ds.FindOne(); 
    hacked = DateTime.FromFileTime((long)sr.Properties["pwdLastSet"][0]); 




All Articles