Posts RSS Comments RSS 253 Posts and 411 Comments till now

userAccountControl and “User cannot change password”

Someone asked me a question about setting the “User cannot change password” check box in ADUC. They were creating the user account and setting PASSWD_CANT_CHANGE along with other settings (see my post about HERE about userAccountControl and values) and they couldn’t figure out why the check box wasn’t being applied.

I thought about this, and my first impression was they had the wrong bit value. So, I posted the “correct” one. They came back and said “That didn’t work.”

Hmmm, that’s curious. I turned to Dean and asked him if I was missing something obvious (I had a nagging feeling I had been here before) and he informed me that it has to be set with an “Extended Right” (control access right) via an ACE.

DOH! Now the whole scenario I had THAT feeling about came back to me. I recall having this discussion with someone and providing them a Script that would set the ACE. I searched for the script and I couldn’t find it. This happens to me a lot so I decided a while ago… when I run across this again, BLOG IT!

Technical Info:

In the past, permissions on the ‘userAccountControl’ attribute could be edited oftentimes making the effective password policy moot, i.e. you could end up with accounts that don’t comply with the domain’s password policy.

In Windows 2000, you can’t easily prevent this except by using third party front-end/provisioning tools to manage user objects. In Windows 2003 and later, you can use three newly-added extended rights (Control Access Rights) to prevent these bits from being edited even when the caller has permission to do so. The three (new) ‘Extended Rights’ are –

• Update password not required bit [controls ‘password not required’ and maps to ACE in footnote below]
• Enable per user reversible encryption [controls whether password is stored reversibly encrypted or not]
• Unexpire password [controls ‘password never expires’]

Each of these extended rights MUST be configured on the domain head and scoped as “This Object only” with ALLOW or DENY for the security principals you designate. By default, ‘Authenticated Users’ is granted an ALLOW ACE for each of the three extended rights. This doesn’t mean any old authenticated user can alter the password related bits in the ‘userAccountControl’ attribute; they still require the permission to modify ‘userAccountControl’.

USAGE SCENARIO – create a single group representing ALL three extended rights (or perhaps ONE group for EACH extended right). Then ACL the group(s) accordingly on the domain head with a DENY ACE. Finally, place the account-administrator users and groups that have management permissions to user objects (i.e. they have write permissions to the ‘userAccountControl’ property) in the group(s) you just created thereby preventing those account-administrators from altering the password related bits on the ‘userAccountControl’ attribute resulting in an enforced password policy.

IMPORTANT NOTE [Observed Behavior] – When viewing or changing a user’s ability to change their own password (User Cannot Change Password) through the GUI, it no longer appears to touch ‘userAccountControl’s bit 0x40 (64) — rather, it simply grant’s the ‘SELF’ security principal ‘ALLOW’ or ‘DENY’ to ‘Change Password’ — this can be easily verified by viewing the DACL.

Modifying User Cannot Change Password (LDAP Provider)

So… Here it is (Set-UserCannotChangePassword.ps1)
User: The sAMAccountName of the User
CheckBox: If passed it checks the box
Default: Remove Check box.

Param($User = $(throw ‘$User is Required’,[switch]$CheckBox)

$Searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"","(&(objectcategory=User)(sAMAccountName=$user))")
$MyUser = $Searcher.FindOne().GetDirectoryEntry()

if(!$?){" !! Failed to Get User !!";Return}

    Write-Host " – Checking Box for User [$($MyUser.distinguishedName)]"
    $self = [System.Security.Principal.SecurityIdentifier]‘S-1-5-10’
    $ExtendedRight = [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight
    $deny = [System.Security.AccessControl.AccessControlType]::Deny
    $selfDeny = new-object System.DirectoryServices.ActiveDirectoryAccessRule($self,$ExtendedRight,$deny,‘ab721a53-1e2f-11d0-9819-00aa0040529b’)
    Write-Host " – Removing Check Box for User [$($MyUser.distinguishedName)]"
    $ACL = $MyUser.psbase.get_ObjectSecurity().GetAccessRules($true,$false, [System.Security.Principal.NTAccount])
    $ACEs = $ACL | ?{($_.ObjectType -eq ‘ab721a53-1e2f-11d0-9819-00aa0040529b’) -and ($_.AccessControlType -eq ‘Deny’)}
    foreach($ACE in $ACEs){if($ACE){[void]$MyUser.psbase.get_ObjectSecurity().RemoveAccessRule($ACE)}}


3 Responses to “userAccountControl and “User cannot change password””

  1. on 18 Jul 2008 at 12:23 amjoe

    Couple of items…

    1. user isn’t an objectcategory. Your query is going to be changed by the QP to be (&(objectcategory=person)(samaccountname=userid)). Since the sAMAccountName has to be unique in the domain and is indexed, you can drop that whole first part of the query anyway.

    2. To prevent a user from changing their password, you don’t have to set a DENY ACE. In fact I would recommend not setting a DENY ACE as they are messy. You just need to remove the GRANT Change Password ACEs. That would make it a passive deny.

    3. If you are going to put DENY’s into place, if you want to use SELF, then you also need to put one in for EVERYONE else the user will simply make the change when they aren’t logged in as themselves.

    4. You should remove the explicit GRANTS regardless. No reason to leave them there.

    5. I don’t think ADUC does it correctly either.

  2. on 18 Jul 2008 at 12:29 amjoe


    > Update password not required bit [controls ‘password not required’ and maps to ACE in footnote below]

    this piece doesn’t play into the script at all. Password Not Required and User Can’t Change Password are two different things.

  3. on 18 Jul 2008 at 12:31 amjoe

    And also… 😉

    I believe if you use the WinNT ADSI provider to set the password cannot be changed flag it will set the ACEs for you. However, it will require account op rights at a minimum to use due to its use of legacy NET API calls.

Trackback this post | Feed on Comments to this post

Leave a Reply

You must be logged in to post a comment.