Active Directory - check if password never expires?

10,111

Solution 1

public bool isPasswordExpired(String p_UserName, String p_DomainName)
{
    bool m_Check=false;

    int m_Val1 = (int)de1.Properties["userAccountControl"].Value;
    int m_Val2 = (int) 0x10000;

    if (Convert.ToBoolean(m_Val1 & m_Val2))
    {
        m_Check = true;
    } //end

    return m_Check
}

Solution 2

If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:

Basically, you can define a domain context and easily find users and/or groups in AD:

// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");

if(user != null)
{
   // one of the properties exposed is "PasswordNeverExpires" (bool)
   if(user.PasswordNeverExpires)
   { 
      // do something here....      
      ...   
   }
}

The new S.DS.AM makes it really easy to play around with users and groups in AD!

Solution 3

For .NET 2.0 you can use some LDAP. The magic part is userAccountControl:1.2.840.113556.1.4.803:=65536. The first part is the property that you want to search, the second means "bitwise AND" and the third is the bitwise flag to check, in this case the 17th bit. You can see more on the bitwise AND and OR in Active Directory in How to query Active Directory by using a bitwise filter.

In the code below update the SearchRoot variable with your domain controller (DC) and FQDN.

Imports System.DirectoryServices

Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ''//Bind to the root of our domain
        ''//    YOU_DOMAIN_CONTROLLER should be one of your DCs
        ''//    EXAMPLE and COM are the parts of your FQDN
        Dim SearchRoot As DirectoryEntry = New DirectoryEntry("LDAP://YOUR_DOMAIN_CONTROLLER/dc=EXAMPLE,dc=COM")

        ''//Create a searcher bound to the root
        Dim Searcher As DirectorySearcher = New DirectorySearcher(SearchRoot)

        ''//Set our filer. The last part is dumb but that is the way that LDAP was built.
        ''//It basically does a bitwise AND looking for the 17th bit to be set on that property "userAccountControl" which is the "password never expires" bit
        ''//See this if you care to learn more http://support.microsoft.com/kb/269181
        Searcher.Filter = "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=65536))"
        ''//Find all of the results

        Dim Results = Searcher.FindAll()
        Dim DE As DirectoryEntry

        ''//Loop through each result
        For Each R As SearchResult In Results

            ''//Get the result as a DirectoryEntry object
            DE = R.GetDirectoryEntry()

            ''//Output the object name
            Console.WriteLine(DE.Name)
        Next
    End Sub

End Class

Solution 4

You could use the following code originally from here that I've translated from C# and modified a little bit according to your question (added a getter):

Dim pwdNeverExpires = getPasswordNeverExpires("Tim")
setPasswordNeverExpires("Tim", True)

' See http://msdn.microsoft.com/en-us/library/aa772300(VS.85).aspx
<Flags()> _
Private Enum ADS_USER_FLAG_ENUM
    ADS_UF_SCRIPT = 1
    ' 0x1
    ADS_UF_ACCOUNTDISABLE = 2
    ' 0x2
    ADS_UF_HOMEDIR_REQUIRED = 8
    ' 0x8
    ADS_UF_LOCKOUT = 16
    ' 0x10
    ADS_UF_PASSWD_NOTREQD = 32
    ' 0x20
    ADS_UF_PASSWD_CANT_CHANGE = 64
    ' 0x40
    ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 128
    ' 0x80
    ADS_UF_TEMP_DUPLICATE_ACCOUNT = 256
    ' 0x100
    ADS_UF_NORMAL_ACCOUNT = 512
    ' 0x200
    ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 2048
    ' 0x800
    ADS_UF_WORKSTATION_TRUST_ACCOUNT = 4096
    ' 0x1000
    ADS_UF_SERVER_TRUST_ACCOUNT = 8192
    ' 0x2000
    ADS_UF_DONT_EXPIRE_PASSWD = 65536
    ' 0x10000
    ADS_UF_MNS_LOGON_ACCOUNT = 131072
    ' 0x20000
    ADS_UF_SMARTCARD_REQUIRED = 262144
    ' 0x40000
    ADS_UF_TRUSTED_FOR_DELEGATION = 524288
    ' 0x80000
    ADS_UF_NOT_DELEGATED = 1048576
    ' 0x100000
    ADS_UF_USE_DES_KEY_ONLY = 2097152
    ' 0x200000
    ADS_UF_DONT_REQUIRE_PREAUTH = 4194304
    ' 0x400000
    ADS_UF_PASSWORD_EXPIRED = 8388608
    ' 0x800000
    ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 16777216
    ' 0x1000000
End Enum

Protected Overridable Function getPasswordNeverExpires(ByVal userName As String) As Boolean
    Const userNameString As String = "userName"
    Const userFlagsString As String = "userFlags"

    Dim machineName As String = Environment.MachineName

    Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
    If userInThisComputerDirectoryEntry Is Nothing Then
        Throw New ArgumentException("not found in " & machineName, userNameString)
    End If

    Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)
    Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)

    Return userFlags = (userFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
End Function

Protected Overridable Sub setPasswordNeverExpires(ByVal userName As String, ByVal passwordNeverExpires As Boolean)
    Const userNameString As String = "userName"
    Const userFlagsString As String = "userFlags"

    Dim machineName As String = Environment.MachineName

    Dim userInThisComputerDirectoryEntry As DirectoryEntry = getUserInThisComputerDirectoryEntry(machineName, userName)
    If userInThisComputerDirectoryEntry Is Nothing Then
        Throw New ArgumentException("not found in " & machineName, userNameString)
    End If

    Dim userFlagsProperties As PropertyValueCollection = userInThisComputerDirectoryEntry.Properties(userFlagsString)

    Dim userFlags As ADS_USER_FLAG_ENUM = CType(userFlagsProperties.Value, ADS_USER_FLAG_ENUM)
    Dim newUserFlags As ADS_USER_FLAG_ENUM = userFlags

    If passwordNeverExpires Then
        newUserFlags = newUserFlags Or ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD
    Else
        newUserFlags = newUserFlags And (Not ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD)
    End If

    userFlagsProperties.Value = newUserFlags

    userInThisComputerDirectoryEntry.CommitChanges()
End Sub

Protected Overridable Function getUserInThisComputerDirectoryEntry(ByVal machineName As String, ByVal userName As String) As DirectoryEntry
    Dim computerDirectoryEntry As DirectoryEntry = getComputerDirectoryEntry(machineName)

    Const userSchemaClassName As String = "user"
    Return computerDirectoryEntry.Children.Find(userName, userSchemaClassName)
End Function

Protected Overridable Function getComputerDirectoryEntry(ByVal machineName As String) As DirectoryEntry
    'Initiate DirectoryEntry Class To Connect Through WINNT Protocol
    ' see: http://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.path.aspx
    Const pathUsingWinNTComputerMask As String = "WinNT://{0},computer"
    Dim path As String = String.Format(pathUsingWinNTComputerMask, machineName)
    Dim thisComputerDirectoryEntry As New DirectoryEntry(path)
    Return thisComputerDirectoryEntry
End Function

You have to add a reference to System.DirectoryServices. I have tested it on Windows Server 2008 with .NET Framework 4 (it should also work under 2.0) without Active Directory. But check it out yourself and feel free to extend it to get/set other properties as well or connect to other machines (SomeDomain/OtherComputerName instead of Environment.MachineName).

Share:
10,111
Madam Zu Zu
Author by

Madam Zu Zu

Updated on June 05, 2022

Comments

  • Madam Zu Zu
    Madam Zu Zu almost 2 years

    Is there a way in Visual Basic to check if the user's password is set to never expire in Active Directory?

    I've found a way to find the last date it was changed, but I can't find the other available options.

    Dim de As DirectoryServices.DirectoryEntry = GetUser(uDetails.username)
    Dim objUser = GetObject(de.Path)
    If objUser.PasswordLastChanged < DateTime.Now.AddMonths(-3) Then
    ...
    

    Where can I find a list of all available objUser properties?

  • Tim Schmelter
    Tim Schmelter over 12 years
    That bites! I've changed this setting on the server to test above methods. That's why today some tasks failed to start with Error Value 2147943730 because i need to renew my password ^^