[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 6896
  • Last Modified:

Unable to Retrieve Password Age (MaxPwdAge) in Active Directory using ADSI

I'm having trouble retrieving the MaxPwdAge using ADSI in both C# and VBscript. For VBscript, I'm using this this code snippet:

***************************************************

Const ONE_HUNDRED_NANOSECOND = .000000100   ' .000000100 is equal to 10^-7
Const SECONDS_IN_DAY = 86400

Set objDomain = GetObject("LDAP://DC=**,DC=****,DC=***")     ' LINE 4
Set objMaxPwdAge = objDomain.Get("maxPwdAge")              ' LINE 5

If objMaxPwdAge.LowPart = 0 Then
  WScript.Echo "The Maximum Password Age is set to 0 in the " & _
               "domain. Therefore, the password does not expire."
  WScript.Quit
Else
  dblMaxPwdNano = Abs(objMaxPwdAge.HighPart * 2^32 + objMaxPwdAge.LowPart)
  dblMaxPwdSecs = dblMaxPwdNano * ONE_HUNDRED_NANOSECOND   ' LINE 13
  dblMaxPwdDays = Int(dblMaxPwdSecs / SECONDS_IN_DAY)      ' LINE 14
  WScript.Echo "Maximum password age: " & dblMaxPwdDays & " days"
End If

*************************************************

Whenever I run this code, I always get a 0 return value. However, when checking the domain controler policy settings, it clearly states that the maximum password age is set to 90 days.

Here's the C# code snippet:

****************************************************
private DateTime GetPasswordAge()
{
     const double ONE_HUNDRED_NANOSECOND = .000000100;
     const double SECONDS_IN_A_DAY = 86400;
 
     DateTime temp;
     DirectoryEntry de = new DirectoryEntry("LDAP://DC=AD,DC=FGMC,DC=COM");//, "Service", "ncc-42136", m_AuthTypes);
     de.RefreshCache();
               

     System.Int64 largeInt = 0;
     IADsLargeInteger li = (IADsLargeInteger)de.Properties["maxPwdAge"].Value;
     largeInt = li.HighPart * 2^32 + li.LowPart;
     double dblMaxPwdSecs = largeInt * ONE_HUNDRED_NANOSECOND;
     double dblMaxPwdDays = (int)dblMaxPwdSecs / SECONDS_IN_A_DAY;
               

     temp = DateTime.FromFileTime(largeInt);
     de.Close();
     de.Dispose();
     de = null;
     return temp;
}

***********************************************

I basically get the same value...

Anyone who can get me straightened out with this delima will be awarded 500 pts!!!!

(We're using windows 2003 server and I'm using visual studio 2003)

Thanks!
0
afking8268
Asked:
afking8268
  • 5
  • 5
  • 4
2 Solutions
 
Bob LearnedCommented:
Did you just recently add, and delete this question?

Bob
0
 
afking8268Author Commented:
Yes, I did. I thought that Programming was too broad and transfering it .NET would be a more appropriate group for the question. I didn't know if there was an easier way of doing it rather than deleting and adding it again.
0
 
Bob LearnedCommented:
Right, that's where I saw it :)  Does the user that you are running with have administrative rights?

Bob
0
Windows Server 2016: All you need to know

Learn about Hyper-V features that increase functionality and usability of Microsoft Windows Server 2016. Also, throughout this eBook, you’ll find some basic PowerShell examples that will help you leverage the scripts in your environments!

 
afking8268Author Commented:
Yes, I'm running it and I have domain admin rights...
0
 
Bob LearnedCommented:
I would return the calculated days, and not try to convert it to a date.  I didn't need any arguments for the DirectoryEntry().  The value for MaxPwdDays should be negative (i.e. -90 for me).

private double GetPasswordAge()
{
     const double ONE_HUNDRED_NANOSECOND = .000000100;
     const double SECONDS_IN_A_DAY = 86400;
 
     DateTime temp;
     DirectoryEntry de = new DirectoryEntry();
     de.RefreshCache();
               
     System.Int64 largeInt = 0;
     IADsLargeInteger li = (IADsLargeInteger)de.Properties["maxPwdAge"].Value;
     largeInt = li.HighPart * 2^32 + li.LowPart;
     double dblMaxPwdSecs = largeInt * ONE_HUNDRED_NANOSECOND;
     double dblMaxPwdDays = -((int)dblMaxPwdSecs / SECONDS_IN_A_DAY);
               
     de.Close();
     de.Dispose();
     de = null;
     return dblMaxPwdDays;
}


Bob
0
 
ihenryCommented:
In C#, I don't need IADsLargeInteger interface to do that. And it returns value exactly as shown in domain GPO editor.

      DirectoryEntry de = new DirectoryEntry();
//      de.Path = String.Format( "LDAP://192.168.1.2/{0}", GetDnsHostFromRootDSE() );
      de.Path = @"LDAP://DC=AD,DC=FGMC,DC=COM";
      de.Username = @"domain\user
      de.Password = @"password";

      DirectorySearcher searcher  = new DirectorySearcher( de );
      searcher.PropertiesToLoad.Add("maxPwdAge");
      try
      {
            SearchResult result = searcher.FindOne();
            Int64 int64Val = (Int64) result.Properties["maxPwdAge"][0];
            int hLi = (int) (int64Val >> 32);
            int lLi = (int) (int64Val & 0xFFFFFFFF);
            long maxPwdAge = (long) ( (hLi * Math.Pow(2, 32)) + lLi) / -864000000000;
      }
      catch
      {
            throw;
      }
      finally
      {
            de.Close(); de.Dispose();
            searcher.Dispose();
      }
0
 
afking8268Author Commented:
TheLearnedOne: I'm still getting a 0 value from your code...

jhenry: I'm getting a large number from your code... :10675199

I'm want to make sure I'M getting this right... the max password field I'm refering to is under the Default Domain Security Settings under Account Policy - Password Policy... Not sure if there's any other location you could set it. Anyway, just wanted to throw that in case I was looking at the wrong domain field.
0
 
ihenryCommented:
That's very strange..I just tested my code in 2 environments (just in case I missed anything). Win2K (3 DCs) and Win2K3 (single DC), all showing the correct value (91 and 42).

If you open gpedit.msc snap-ins from domain controller machine, what do you see? Or bind to rootDSE, get defaultNamingContext attribute value and use it for the ldap path. Then try again run the code.
0
 
ihenryCommented:
Or another way to see the actual value of maxPwdAge of your domain is using softerra ldap browser(free download utility). Browse your domain and find the maxPwdAge attribute, then calculate its value using calculator, for example -77760000000000 / -864000000000 = 90 days.
0
 
Bob LearnedCommented:
I had -77760000000000 for the value.

Bob
0
 
afking8268Author Commented:
jhenry, TheLearnedOne:
Ok, I downloaded the ldap browser... also i opened gpedit.msc. It seems there are a few places you could set the domain policies... In W2K3 I'm setting it under Default Domain Security Settings -> Security Settings -> Account Policies -> Password Policy

gpedit is the group policy editor for the local computer (w/c also happens to be a Domain Controller). When I changed the values there.. then all your suggestions worked! Is this the right place to set the values? What's the Default Domain Security Settings for then...? And, if I change the values in the group policy editor, will it replicate through all our DCs?
0
 
Bob LearnedCommented:
AFAIK, When you are a member of a domain, policies are applied in descending order from enterprise -> machine.  If you haven't overriden any of the domain policies, then they should apply to each machine that is a member of the domain.

I haven't used 2003 Server, so I can't comment on Default Domain Security Settings.

Bob
0
 
ihenryCommented:
Well, it's actually configurable. I don't know what group policy applied to your domain, but you can check that from "Active Directory Users and Computers" console. On the left pane, right-click on your domain node, select Properties, click on "Group Policy" tab. Try to play around a little by adding/removing group policy and see how the changes effects to the maxPwdAge :o)
0
 
afking8268Author Commented:
Thanks for all your help...!!
0

Featured Post

Prepare for your VMware VCP6-DCV exam.

Josh Coen and Jason Langer have prepared the latest edition of VCP study guide. Both authors have been working in the IT field for more than a decade, and both hold VMware certifications. This 163-page guide covers all 10 of the exam blueprint sections.

  • 5
  • 5
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now