Announcement

Collapse
No announcement yet.

All users must change password at next login

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • All users must change password at next login

    I am trying to write a script that will force all users in my domain to change their password at next login, but I want to skip the accounts that have their passwords set to never expire. This is what I came up with, but it is kindof hard to test, unless I want to screw up my whole domain...lol. Can anyone help?

    Code:
    Set objRootDSE = GetObject("LDAP://rootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext")
    
    Set objConnection = CreateObject("ADODB.Connection")
    Set objCommand =   CreateObject("ADODB.Command")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open "Active Directory Provider"
    Set objCommand.ActiveConnection = objConnection
    
    objCommand.Properties("Page Size") = 1000
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
    
    objCommand.CommandText = _
        "SELECT AdsPath FROM 'LDAP://" & strDNSDomain & "' WHERE " _
        & "objectCategory='person' AND ObjectClass='user'"
    
    Set objRecordSet = objCommand.Execute
    If not objRecordSet.EOF Then 
      objRecordSet.MoveFirst
      Do Until objRecordSet.EOF
          Set objUser = GetObject(objRecordSet.Fields("AdsPath").Value)
    
    'On Error Resume Next
    If objUser.PasswordExpired = 0 Then
    objRecordSet.MoveNext
       Else
          objUser.Put "PwdLastSet", 0
          objUser.SetInfo
       End If
    objRecordSet.MoveNext
    Loop
    On Error GoTo 0
    
    msgbox "All users will now change their password at next login!"

  • #2
    Re: All users must change password at next login

    If you have the account options set for 'password never expires' you may not set the attribrute 'user must change password at next logon'. You will receive an error message similar to 'the user will not be required to change password at next logon'.

    You could possibly write an error coniditon for the above being returned when appling and setting attribrute value.

    You could move/create adomain controller and isolate this from the network using IPSec and test this or create a test domain environment. You could also download AD Toolkit from Javalina Software which allows you to make bulk Active Directory modifications from a GUI and contains a simulation mode. Alternatively limit you testing to handful of users until you are confident. I am sure there will be a number fo applications out there that are similar and include simulation mode.
    MCSA 2000/2003

    Comment


    • #3
      Re: All users must change password at next login

      This part will not skip that?

      Code:
      If objUser.PasswordExpired = 0 Then
      objRecordSet.MoveNext

      Comment


      • #4
        Re: All users must change password at next login

        I would imagine so as the objUser.PasswordExpired value 0 is equal to not enabled, i presume this is similar to the below where the user account control value is used for the password property when binded to a single user

        Code:
        If Not objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then
        MCSA 2000/2003

        Comment


        • #5
          Re: All users must change password at next login

          Yeah I was just looking at that way too, looks like this might work as well:

          Code:
          Const ADS_UF_PASSWD_CANT_CHANGE = &H0040
          Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
          Const ADS_UF_ACCOUNTDISABLE = &H0002
          
          Set objRootDSE = GetObject("LDAP://rootDSE")
          strDNSDomain = objRootDSE.Get("defaultNamingContext")
          
          Set objConnection = CreateObject("ADODB.Connection")
          Set objCommand =   CreateObject("ADODB.Command")
          objConnection.Provider = "ADsDSOObject"
          objConnection.Open "Active Directory Provider"
          Set objCommand.ActiveConnection = objConnection
          
          objCommand.Properties("Page Size") = 1000
          objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
          
          objCommand.CommandText = _
              "SELECT AdsPath FROM 'LDAP://" & strDNSDomain & "' WHERE " _
              & "objectCategory='person' AND ObjectClass='user'"
          
          Set objRecordSet = objCommand.Execute
          If not objRecordSet.EOF Then 
            objRecordSet.MoveFirst
            Do Until objRecordSet.EOF
                Set objUser = GetObject(objRecordSet.Fields("AdsPath").Value)
          
          'On Error Resume Next
          
          If objUser.UserFlags AND ADS_UF_PASSWD_CANT_CHANGE _
          	OR objUser.UserFlags AND ADS_UF_DONT_EXPIRE_PASSWD _
          	OR objUser.UserFlags AND ADS_UF_ACCOUNTDISABLE Then
          'If objUser.PasswordExpired = 0 Then
          objRecordSet.MoveNext
             Else
                objPasswordNoChangeFlag = objUser.UserFlags XOR ADS_UF_PASSWD_CANT_CHANGE
                objUser.Put "userFlags", objPasswordNoChangeFlag 
                objUser.Put "PwdLastSet", 0
                objUser.SetInfo
             End If
          objRecordSet.MoveNext
          Loop
          On Error GoTo 0
          
          msgbox "All users will now change their password at next login!"
          *Edit-- Actually take out that part in red...
          Last edited by ekrengel; 18th January 2008, 17:06. Reason: mistake

          Comment


          • #6
            Re: All users must change password at next login

            So this completes without any errors, but nothing gets changed...

            Code:
            Const ADS_UF_PASSWD_CANT_CHANGE = &H0040
            Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
            Const ADS_UF_ACCOUNTDISABLE = &H0002
            
            Set objRootDSE = GetObject("LDAP://rootDSE")
            strDNSDomain = objRootDSE.Get("defaultNamingContext")
            
            Set objConnection = CreateObject("ADODB.Connection")
            Set objCommand =   CreateObject("ADODB.Command")
            objConnection.Provider = "ADsDSOObject"
            objConnection.Open "Active Directory Provider"
            Set objCommand.ActiveConnection = objConnection
            
            objCommand.Properties("Page Size") = 1000
            objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
            
            objCommand.CommandText = _
                "SELECT AdsPath FROM 'LDAP://" & strDNSDomain & "' WHERE " _
                & "objectCategory='person' AND ObjectClass='user'"
            
            Set objRecordSet = objCommand.Execute
            If not objRecordSet.EOF Then 
              objRecordSet.MoveFirst
              Do Until objRecordSet.EOF
                  Set objUser = GetObject(objRecordSet.Fields("AdsPath").Value)
            
            'On Error Resume Next
            
            If objUser.UserFlags AND ADS_UF_PASSWD_CANT_CHANGE _
            	OR objUser.UserFlags AND ADS_UF_DONT_EXPIRE_PASSWD _
            	OR objUser.UserFlags AND ADS_UF_ACCOUNTDISABLE Then
            'If objUser.PasswordExpired = 0 Then
            objRecordSet.MoveNext
               Else
                  objUser.Put "PwdLastSet", 0
                  objUser.SetInfo
               End If
            objRecordSet.MoveNext
            Loop
            End IF
            On Error GoTo 0
            
            msgbox "All users will now change their password at next login!"
            *I'm running this in a test VMware machine that I created.
            Last edited by ekrengel; 30th January 2008, 13:44.

            Comment


            • #7
              Re: All users must change password at next login

              This still isn't working...I've tried all these different ways that say it can do it, but I'm not getting any profiles changed.

              Code:
              Const ADS_UF_PASSWD_CANT_CHANGE = &H0040
              Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
              Const ADS_UF_ACCOUNTDISABLE = &H0002
              
              Set objRootDSE = GetObject("LDAP://rootDSE")
              strDNSDomain = objRootDSE.Get("defaultNamingContext")
              
              Set objConnection = CreateObject("ADODB.Connection")
              Set objCommand =   CreateObject("ADODB.Command")
              objConnection.Provider = "ADsDSOObject"
              objConnection.Open "Active Directory Provider"
              Set objCommand.ActiveConnection = objConnection
              
              objCommand.Properties("Page Size") = 1000
              objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
              
              objCommand.CommandText = _
                  "SELECT AdsPath FROM 'LDAP://" & strDNSDomain & "' WHERE " _
                  & "objectCategory='person' AND ObjectClass='user'"
              
              Set objRecordSet = objCommand.Execute
              If not objRecordSet.EOF Then 
                objRecordSet.MoveFirst
                Do Until objRecordSet.EOF
                    Set objUser = GetObject(objRecordSet.Fields("AdsPath").Value)
              
              'On Error Resume Next
              
              If objUser.UserFlags AND ADS_UF_PASSWD_CANT_CHANGE _
              	OR objUser.UserFlags AND ADS_UF_DONT_EXPIRE_PASSWD Then
              objRecordSet.MoveNext
                 Else
                    objUser.PasswordExpired = 1
                    'objUser.pwdLastSet = 0
                    'objUser.Put "pwdLastSet", 0
                    objUser.SetInfo
                 End If
              objRecordSet.MoveNext
              Loop
              End IF
              On Error GoTo 0
              
              msgbox "All users will now change their password at next login!"

              Comment


              • #8
                Re: All users must change password at next login

                You just forgot defining the constant ADS_SCOPE_SUBTREE = 2


                Filter the bit like this;
                ' http://msdn2.microsoft.com/en-us/library/ms680832.aspx (User-Account-Control Attribute)

                (For explanation of the blue colored text in the code below, see my next reply)
                Code:
                '// http://forums.petri.com/showthread.php?t=20923
                
                Const ADS_SCOPE_SUBTREE = 2
                Const ADS_UF_PASSWD_CANT_CHANGE = &H40
                Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
                
                
                Set objWinNTSysInfo = CreateObject("WinNTSystemInfo")
                strNetBIOSDomain = objWinNTSysInfo.DomainName
                
                Set objRootDSE = GetObject("LDAP://rootDSE")
                strDNSDomain = objRootDSE.Get("defaultNamingContext")
                
                Set objConnection = CreateObject("ADODB.Connection")
                Set objCommand =   CreateObject("ADODB.Command")
                objConnection.Provider = "ADsDSOObject"
                objConnection.Open "Active Directory Provider"
                Set objCommand.ActiveConnection = objConnection
                
                objCommand.Properties("Page Size") = 1000
                objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
                
                objCommand.CommandText = _
                    "SELECT AdsPath,sAMAccountName FROM 'LDAP://" & strDNSDomain _
                    & "' WHERE objectCategory='person' AND ObjectClass='user'"
                
                ' Run the query.
                Set objRecordSet = objCommand.Execute
                
                If not objRecordSet.EOF Then 
                  objRecordSet.MoveFirst
                  Do Until objRecordSet.EOF
                
                '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                     Set objUser = GetObject("WinNT://" & strNetBIOSDomain & "/" _
                       & objRecordSet.Fields("sAMAccountName").Value & ",User")
                
                      lngFlag = objUser.Get("userFlags")  'instead of "userAccountControl"
                      If ((lngFlag And ADS_UF_PASSWD_CANT_CHANGE) <> 0) Then
                          blnPwdExpire = False
                      ElseIf ((lngFlag And ADS_UF_DONT_EXPIRE_PASSWD) <> 0) Then
                          blnPwdExpire = False
                      Else
                          blnPwdExpire = True
                      End If
                '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                      If (blnPwdExpire = True) then
                          objUser.Put "PasswordExpired", CLng(1)  ' User must change password.
                          objUser.SetInfo
                      End If
                     Set objUser = Nothing
                '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                
                     objRecordSet.MoveNext
                  Loop
                End If
                
                ' Clean up.
                objRecordset.Close
                objConnection.Close
                Set objRootDSE = Nothing
                Set objConnection = Nothing
                Set objRecordSet = Nothing
                - OR -
                FYI, there is also a possibility to filter by these kind of bits using a filterstring in the LDAP-query,
                ' http://support.microsoft.com/?kbid=269181 (using the bitwise filter)
                Code:
                '// http://forums.petri.com/showthread.php?t=20923
                
                '// UserAccountControl Flags (ADS_UF_);
                '//    PASSWD_CANT_CHANGE * = 0x0040 (&H40) = 64
                '//    DONT_EXPIRE_PASSWORD = 0x10000 (&H10000) = 65536 
                '// http://support.microsoft.com/kb/305144
                '//
                '// *)Note, 
                '//   the PASSWD_CANT_CHANGE field cannot be looked up using these attributes !!
                '//  That means that for those users this bit is going to
                '//  be cleared by this script!!!!!!!  as soon as the
                '//  Must_Change_Passw_At_Next_Login' is configured. And these users now
                '//  must change their password at next logon!
                
                Set objRootDSE = GetObject("LDAP://RootDSE")
                strDNSDomain = objRootDSE.Get("defaultNamingContext")
                
                Set objConnection = CreateObject("ADODB.Connection")
                Set objCommand =   CreateObject("ADODB.Command")
                objConnection.Provider = "ADsDSOObject"
                objConnection.Open "Active Directory Provider"
                Set objCommand.ActiveConnection = objConnection
                
                objCommand.Properties("Page Size") = 100
                objCommand.Properties("Timeout") = 30
                objCommand.Properties("Cache Results") = False
                 
                ' Filter on user objects. (http://www.rlmueller.net/ADOSearchTips.htm)
                strFilter = "(&(objectCategory=person)(objectClass=user)" _
                    & "(!userAccountControl:1.2.840.113556.1.4.803:=65536))"
                
                objCommand.CommandText = _
                    "<LDAP://" & strDNSDomain & ">"  & ";" & strFilter & ";AdsPath;subtree"
                
                ' Run the query.
                Set objRecordSet = objCommand.Execute
                
                If not objRecordSet.EOF Then 
                  objRecordSet.MoveFirst
                  Do Until objRecordSet.EOF
                
                '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                      Set objUser = GetObject(objRecordSet.Fields("AdsPath").Value)
                         objUser.Put "pwdLastSet", 0
                         objUser.SetInfo
                      Set objUser = Nothing
                '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                
                     objRecordSet.MoveNext
                  Loop
                End If
                
                ' Clean up.
                objRecordset.Close
                objConnection.Close
                Set objRootDSE = Nothing
                Set objConnection = Nothing
                Set objRecordSet = Nothing 
                Because the second script would also reset the "User_Cannot_Change_Password" bit for the users where this was checked,
                the first script is there for the best choice of these two for this topic !

                \Rems
                Last edited by Rems; 6th February 2008, 00:00. Reason: edits are colored blue

                This posting is provided "AS IS" with no warranties, and confers no rights.

                __________________

                ** Remember to give credit where credit's due **
                and leave Reputation Points for meaningful posts

                Comment


                • #9
                  Re: All users must change password at next login

                  Doh! It's always something little...I'll test it out when I get home. Thanks.

                  Comment


                  • #10
                    Re: All users must change password at next login

                    Ok so that worked with using "http://www.rlmueller.net/Programs/PwdLastSet.txt", but for a user that has "Password cannot be changed" checked, they are still being applied for changing their password at next login...I tried this, but it also had the user force a pass change when their pass cannot be changed:

                    Code:
                          If ((lngFlag And ADS_UF_PASSWD_CANT_CHANGE) <> 0) _
                           OR ((lngFlag And ADS_UF_DONT_EXPIRE_PASSWD) <> 0) Then
                              blnPwdExpire = False
                          Else
                              blnPwdExpire = True
                          End If

                    Comment


                    • #11
                      Re: All users must change password at next login

                      Well...after scrapping some parts together from other scripts on the net, I came up with this, and it works...

                      Code:
                      Const ADS_SCOPE_SUBTREE = 2
                      Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
                      Const ADS_UF_ACCOUNTDISABLE = &H0002
                      Const CHANGE_PASSWORD_GUID = "{AB721A53-1E2F-11D0-9819-00AA0040529B}"
                      
                      Set objRootDSE = GetObject("LDAP://rootDSE")
                      strDNSDomain = objRootDSE.Get("defaultNamingContext")
                      
                      Set objConnection = CreateObject("ADODB.Connection")
                      Set objCommand =   CreateObject("ADODB.Command")
                      objConnection.Provider = "ADsDSOObject"
                      objConnection.Open "Active Directory Provider"
                      Set objCommand.ActiveConnection = objConnection
                      
                      objCommand.Properties("Page Size") = 1000
                      objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
                      
                      objCommand.CommandText = _
                          "SELECT AdsPath FROM 'LDAP://" & strDNSDomain & "' WHERE " _
                          & "objectCategory='person' AND ObjectClass='user'"
                      
                      Set objRecordSet = objCommand.Execute
                      
                      While Not objRecordset.EOF
                       strADsPath = objRecordset.Fields("ADsPath")
                       Set objUser = GetObject(strADsPath)
                      
                      intUAC = objUser.Get("userAccountControl")
                       bChange = True
                      
                       Set oSecDesc = objUser.Get("ntSecurityDescriptor")
                       Set oACL = oSecDesc.DiscretionaryAcl
                          
                        For Each oACE In oACL
                          If UCase(oACE.ObjectType) = UCase(CHANGE_PASSWORD_GUID) Then
                             
                            If oACE.Trustee = "NT AUTHORITY\SELF" Then
                              If oACE.AceType <> 5 then
                      		bChange = False
                              End If
                            End If
                          End If
                        Next
                       
                       If (intUAC AND ADS_UF_DONT_EXPIRE_PASSWD) Then
                         bChange = False
                       End If
                      
                       If (intUAC AND ADS_UF_ACCOUNTDISABLE) Then
                         bChange = False
                       End If
                      
                       If bChange Then
                      	objUser.Put "pwdLastSet", 0
                      	objUser.SetInfo
                       End If
                      
                       objRecordset.MoveNext
                      Wend
                      
                      objRecordset.Close
                      objConnection.Close
                      Set objRootDSE = Nothing
                      Set objConnection = Nothing
                      Set objRecordSet = Nothing
                      
                      msgbox "All users will now change their password at next login!"
                      
                      WScript.Quit(0)

                      Comment


                      • #12
                        Re: All users must change password at next login

                        Yes you are right,
                        It seems that the LDAP provider cannot lookup PASSWD_CANT_CHANGE et all (?)


                        - EDIT - Did not notice your solution, before I sent mine
                        looks nice!

                        Reading User Cannot Change Password (LDAP Provider)
                        Const CHANGE_PASSWORD_GUID = "{AB721A53-1E2F-11D0-9819-00AA0040529B}"

                        - - - - - -

                        Reading User Cannot Change Password (WinNT Provider)
                        (and, User Must Change Password at Next Logon (WinNT Provider))

                        Example of using the WinNT provider instead;
                        The major difference is it need the NetBios name of the Domain and the SamAccountname of each user.


                        Code:
                        ' You now also need the NetBiosName of the Domain
                        Set objWinNTSysInfo = CreateObject("WinNTSystemInfo")
                        strNetBIOSDomain = objWinNTSysInfo.DomainName
                        
                        '<cut>  <cut> <cut>
                        
                        ' You now also need the pre-Windows 200 accountname
                        objCommand.CommandText = _
                            "SELECT AdsPath,sAMAccountName FROM 'LDAP://" & strDNSDomain & "' WHERE " _
                            & "objectCategory='person' AND ObjectClass='user'"
                        Code:
                        ' connect the first time to the user's object with the WinNT provider
                        Set objUser = GetObject("WinNT://" & strNetBIOSDomain & "/" & objRecordSet.Fields("sAMAccountName").Value & ",User")
                        ' And read the bits
                              lngFlag = objUser.Get("userFlags")
                              If ((lngFlag And ADS_UF_PASSWD_CANT_CHANGE) <> 0) Then
                                  blnPwdExpire = False
                              ElseIf ((lngFlag And ADS_UF_DONT_EXPIRE_PASSWD) <> 0) Then
                                  blnPwdExpire = False
                              Else
                                  blnPwdExpire = True
                              End If
                        
                              If (blnPwdExpire = True) then
                                  objUser.Put "PasswordExpired", CLng(1)  ' User must change password.
                                  objUser.SetInfo
                              End If
                             Set objUser = Nothing
                        I will edit the example in my previous reply today, the changes will be colored in blue.

                        \Rems
                        Last edited by Rems; 5th February 2008, 18:33. Reason: edit the line: "objUser.Put ...", to work with the WinNT provider

                        This posting is provided "AS IS" with no warranties, and confers no rights.

                        __________________

                        ** Remember to give credit where credit's due **
                        and leave Reputation Points for meaningful posts

                        Comment


                        • #13
                          Re: All users must change password at next login

                          Thanks Rems! That way works as well and looks much cleaner. Thanks again.

                          Comment


                          • #14
                            Re: All users must change password at next login

                            I made a slight improvement.

                            In the previous examples above I used both, the WinNT provider to read the bits,
                            and then the LDAP provider to set the 'User must change password'.

                            I now left the second LDAP binding to the same user object out of the script, by adapting the line: objUser.Put ... to work for the WinNT provider.

                            \Rems

                            This posting is provided "AS IS" with no warranties, and confers no rights.

                            __________________

                            ** Remember to give credit where credit's due **
                            and leave Reputation Points for meaningful posts

                            Comment


                            • #15
                              Re: All users must change password at next login

                              Even better!

                              Comment

                              Working...
                              X