' CanChgPW.vbs ' VBScript program to configure a user so they can change their ' password. ' ' ---------------------------------------------------------------------- ' Copyright (c) 2002-2010 Richard L. Mueller ' Hilltop Lab web site - http://www.rlmueller.net ' Version 1.0 - November 10, 2002 ' Version 1.1 - February 19, 2003 - Standardize Hungarian notation. ' Version 1.2 - January 25, 2004 - Modify error trapping. ' Version 2.0 - December 10, 2009 - Make sure allow ACE remains. ' Version 2.1 - November 6, 2010 - No need to set objects to Nothing. ' The Distinguished Name of the user object is passed to the program as ' a parameter. ' ' You have a royalty-free right to use, modify, reproduce, and ' distribute this script file in any way you find useful, provided that ' you agree that the copyright owner above has no warranty, obligations, ' or liability for such use. Option Explicit Const CHANGE_PASSWORD_GUID = "{AB721A53-1E2F-11D0-9819-00AA0040529B}" Const ADS_RIGHT_DS_CONTROL_ACCESS = &H100 Const ADS_ACETYPE_ACCESS_ALLOWED_OBJECT = &H5 Const ADS_ACETYPE_ACCESS_DENIED_OBJECT = &H6 Const ADS_ACEFLAG_OBJECT_TYPE_PRESENT = &H1 Const ADS_ACETYPE_ACCESS_ALLOWED = &H0 Const ADS_ACETYPE_ACCESS_DENIED = &H1 Const ADS_ACEFLAG_INHERITED_ACE = &H10 Dim objACESelf, objACEEveryone, objSecDescriptor, objDACL, objUser Dim strDN, objACE, blnSelf, blnEveryone, blnModified ' Check for required argument. If (Wscript.Arguments.Count < 1) Then Wscript.Echo "Required argument missing. " _ & "For example:" & vbCrLf _ & "cscript CanChgPW.vbs cn=TestUser,ou=Sales,dc=MyDomain,dc=com" Wscript.Quit(0) End If ' Bind to user object with the LDAP provider. strDN = Wscript.Arguments(0) On Error Resume Next Set objUser = GetObject("LDAP://" & strDN) If (Err.Number <> 0) Then On Error GoTo 0 Wscript.Echo "User not found" & vbCrLf & strDN Wscript.Quit(1) End If On Error GoTo 0 ' Bind to the user security objects. Set objSecDescriptor = objUser.Get("ntSecurityDescriptor") Set objDACL = objSecDescriptor.discretionaryAcl ' Search for the ACE that denies permission to change password and ' change it to allow. blnSelf = False blnEveryone = False blnModified = False For Each objACE In objDACL If (UCase(objACE.Trustee) = "NT AUTHORITY\SELF") _ And (UCase(objACE.objectType) = CHANGE_PASSWORD_GUID) _ And (objACE.AceFlags = 0) _ And (objACE.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS) _ And (objACE.Flags = ADS_ACEFLAG_OBJECT_TYPE_PRESENT) Then If (objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT) Then objACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT blnModified = True End If blnSelf = True End If If (UCase(objACE.Trustee) = "EVERYONE") _ And (UCase(objACE.objectType) = CHANGE_PASSWORD_GUID) _ And (objACE.AceFlags = 0) _ And (objACE.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS) _ And (objACE.Flags = ADS_ACEFLAG_OBJECT_TYPE_PRESENT) Then If (objACE.AceType = ADS_ACETYPE_ACCESS_DENIED_OBJECT) Then objACE.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT blnModified = True End If blnEveryone = True End If Next ' If ACE's found and modified, save changes and exit. If (blnSelf = True) And (blnEveryone = True) Then If (blnModified = False) Then Wscript.Echo "User already can change their password" Wscript.Quit Else objSecDescriptor.discretionaryACL = Reorder(objDACL) objUser.Put "ntSecurityDescriptor", objSecDescriptor objUser.SetInfo Wscript.Echo "User modified so they can change their password" Wscript.Quit End If End If ' If ACE's not found, add to DACL. If (blnSelf = False) Then ' Create the ACE for Self. Set objACESelf = CreateObject("AccessControlEntry") objACESelf.Trustee = "NT AUTHORITY\SELF" objACESelf.AceFlags = 0 objACESelf.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT objACESelf.Flags = ADS_ACEFLAG_OBJECT_TYPE_PRESENT objACESelf.objectType = CHANGE_PASSWORD_GUID objACESelf.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS objDACL.AddAce objACESelf End If If (blnEveryone = False) Then ' Create the ACE for Everyone. Set objACEEveryone = CreateObject("AccessControlEntry") objACEEveryone.Trustee = "Everyone" objACEEveryone.AceFlags = 0 objACEEveryone.AceType = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT objACEEveryone.Flags = ADS_ACEFLAG_OBJECT_TYPE_PRESENT objACEEveryone.objectType = CHANGE_PASSWORD_GUID objACEEveryone.AccessMask = ADS_RIGHT_DS_CONTROL_ACCESS objDACL.AddAce objACEEveryone End If objSecDescriptor.discretionaryACL = Reorder(objDACL) ' Update the user object. objUser.Put "ntSecurityDescriptor", objSecDescriptor objUser.SetInfo Wscript.Echo "User modified so they can change their password" Function Reorder(ByVal objDACL) ' Reorder ACE's in DACL. Dim objNewDACL, objInheritedDACL, objAllowDACL, objDenyDACL Dim objAllowObjectDACL, objDenyObjectDACL, objACE Set objNewDACL = CreateObject("AccessControlList") Set objInheritedDACL = CreateObject("AccessControlList") Set objAllowDACL = CreateObject("AccessControlList") Set objDenyDACL = CreateObject("AccessControlList") Set objAllowObjectDACL = CreateObject("AccessControlList") Set objDenyObjectDACL = CreateObject("AccessControlList") For Each objACE In objDACL If ((objACE.AceFlags And ADS_ACEFLAG_INHERITED_ACE) = _ ADS_ACEFLAG_INHERITED_ACE) Then objInheritedDACL.AddAce objACE Else Select Case objACE.AceType Case ADS_ACETYPE_ACCESS_ALLOWED objAllowDACL.AddAce objACE Case ADS_ACETYPE_ACCESS_DENIED objDenyDACL.AddAce objACE Case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT objAllowObjectDACL.AddAce objACE Case ADS_ACETYPE_ACCESS_DENIED_OBJECT objDenyObjectDACL.AddAce objACE Case Else blnACL = False End Select End If Next For Each objACE In objDenyDACL objNewDACL.AddAce objACE Next For Each objACE In objDenyObjectDACL objNewDACL.AddAce objACE Next For Each objACE In objAllowDACL objNewDACL.AddAce objACE Next For Each objACE In objAllowObjectDACL objNewDACL.AddAce objACE Next For Each objACE In objInheritedDACL objNewDACL.AddAce objACE Next objNewDACL.ACLRevision = objDACL.ACLRevision Set Reorder = objNewDACL End Function