|
|
|||||||
I'm having some difficulty with a routine I'm working on to update the "User cannot change password" option. It's not a simple flag, but rather an access control entry on the discretionary access control list of security discriptor of the user object. I've modified the code I've found on the MS scriptcenter for KIX, but I'm getting a "member not found error" when I attempt to reassign the security descriptor. If I comment out all the code between where I retrieve the DACL and then try to reassign it so that the code would flow as follows: $objDACL=$objSD.DiscretionaryAcl $objSD.DiscretionaryAcl = $objDACL I still get the error on the assign. Any thoughts? Here's the code I have. $ADS_ACETYPE_ACCESS_DENIED_OBJECT=&6 $ADS_ACEFLAG_OBJECT_TYPE_PRESENT=&1 $CHANGE_PASSWORD_GUID = "{AB721A53-1E2F-11D0-9819-00AA0040529B}" $ADS_RIGHT_DS_CONTROL_ACCESS =&100 $objUser=GetObject("LDAP://CN=TestStudent, OU=test, DC=test, DC=local") $test=$objUser.Get("SN") ? "User:"+ $test $objSD=$objUser.Get("ntSecurityDescriptor") $objDACL=$objSD.DiscretionaryAcl ; This is test code to see if the ACE can be read (this works) For Each $Ace In $objDACL ?$ACE.ObjectType+" --> "+$Ace.Acetype If (($Ace.AceType = $ADS_ACETYPE_ACCESS_DENIED_OBJECT) AND (LCase($Ace.ObjectType) = $CHANGE_PASSWORD_GUID)) $blnACEPresent = True EndIf Next If $blnACEPresent ? "ADS_UF_PASSWD_CANT_CHANGE is enabled" Else ? "ADS_UF_PASSWD_CANT_CHANGE is disabled" ENDIF ; Set up the new ACE entries $aryTrustees = "nt authority\self" , "EVERYONE" FOR EACH $strTrustee IN $aryTrustees $objACE = CreateObject("AccessControlEntry") $objACE.Trustee=$strTrustee $objACEFlags=0 $objACE.AceType= $ADS_ACETYPE_ACCESS_DENIED_OBJECT $objACE.Flags = $ADS_ACEFLAG_OBJECT_TYPE_PRESENT $objACE.ObjectType= $CHANGE_PASSWORD_GUID $objACE.AccessMask = $ADS_RIGHT_DS_CONTROL_ACCESS $objDACL.AddAce($objACE) NEXT $objSD.DiscretionaryAcl = $objDACL ? "1:"+@error+" "+@serror $objUser.Put("ntSecurityDescriptor", $objSD) ? "2:"+@error+" "+@serror $objUser.SetInfo ? "3:"+@error+" "+@serror |
||||||||
|
|
|||||||
I think you are headed in the wrong direction. UF_PASSWD_CANT_CHANGE is part of the UserFlags property of the user account. See: AllFlags() - Test to see if all the flags tested are set UsrMustChgPwd() - Force a user to change password at next login This second link will give code very close to what you need. You can also use the WinNT:// provider if you desire. |
||||||||
|
|
|||||||
I had hoped that would be the case. Unfortunately for the Cannot Change Password option, this can only be read from the Userflags property--it can't be set(regardless if it's the LDAP or WINNT interface) To quote the MS Site ADSI reference http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netdir/adsi/adsi_reference.asp To determine if the user has been granted permission to change his or her password, read the ADS_UF_PASSWD_CANT_CHANGE (0x0040) bit on the userFlags attribute of the user object. This flag is defined in the ADS_USER_FLAG_ENUM enumeration. This flag cannot be set directly. To prevent a user from changing the password, set two ACEs in the security descriptor DACL of the user object. One ACE denies the permission to the user and another ACE denies the permission to the Everyone group. Both ACEs are object-specific deny ACEs that specify the GUID of the extended permission for changing passwords. |
||||||||
|
|
|||||||
I just set the UF_PASSWD_CANT_CHANGE flag on NT4 using Perl by performing a Bitwise OR of UserFlags and ($UF_PASSWD_CANT_CHANGE = 0x0040;). I will check KiXtart shortly. {edit} This also worked on a W2K AD DC. [ 25. August 2002, 21:38: Message edited by: Howard Bullock ] |
||||||||
|
|
|||||||
While I can set other flags (for example the ADS_UF_DONT_EXPIRE_PASSWD &10000) using the method you specify, I can't set the ADS_UF_PASSWD_CANT_CHANGE. If I try to set an ADS_UF_PASSWD_CANT_CHANGE(&40), the script will "work" insofar as it won't report any errors; however, checking the user account will show that the flag is not set. Rerunning the script and just displaying the flag will also show that the value is not "saved" after the put. Since I forgot to post it in the original message, I am using an AD under win2k and kixtart 4.10. Here's the script I used to test that out on an account with no flags enabled: $Ouser=GetObject("LDAP://CN=Test, OU=Test, DC=TASD, DC=LOCAL") if @error<>0 ? @error+" "+@serror endif If $oUser ; Print Base $Flags = $oUser.Get("UserAccountControl") ? "Base: "+$Flags ? "ADS_UF_DONT_EXPIRE_PASSWD" $Flags = $oUser.Get("UserAccountControl") $Flags = $Flags | &10000 ? " Before Put:"+$Flags $oUser.Put("UserAccountControl",$Flags) if @error<>0 ? @error+" "+@serror endif $oUser.SetInfo if @error<>0 ? @error+" "+@serror endif ;Check the value again $Flags = $oUser.Get("UserAccountControl") ?" After Put: "+$Flags ?"ADS_UF_PASSWD_CANT_CHANGE" $Flags = $oUser.Get("UserAccountControl") $Flags = $Flags | &40 ? " Before Put:"+$Flags $oUser.Put("UserAccountControl",$Flags) if @error<>0 ? @error+" "+@serror endif $oUser.SetInfo if @error<>0 ? @error+" "+@serror endif ;Check the value again $Flags = $oUser.Get("UserAccountControl") ?" After Put: "+$Flags Else ? "User not found" EndIf $oUser=0 And here's the output: Base: 544 ADS_UF_DONT_EXPIRE_PASSWD Before Put:66080 After Put: 66080 ADS_UF_PASSWD_CANT_CHANGE Before Put:66144 After Put: 66080 This seems to jive with what the Microsoft docs say. Thanks -Glen |
||||||||
|
|
|||||||
This code works. I have yet to test the LDAP:// provider. Notice the difference of my use of "&40". I believe that you need to use the "VAL" function. Test and let me know. code:$Domain = "us-tyco-e" [ 26. August 2002, 01:33: Message edited by: Howard Bullock ] |
||||||||
|
|
|||||||
My statement about the VAL function was incorrect. I spoke before I tested. code:worked too.$Val = $val | &40 [ 26. August 2002, 01:51: Message edited by: Howard Bullock ] |
||||||||
|
|
|||||||
Thanks! It does seem to work properly under the WINNT provider. I was working primarily under the LDAP provider since this was part of a user creation script and I was using LDAP to get the users into the correct OUs. I guess next time I should just try it before reading the documentation from MS Thanks again. (Heck, I'll even buy AMP connectors next time I put in an order ) |
||||||||
|
|
|||||||
I've got the hard part of this issue done, the only problem is that my OR operation is returning the same value. I quickly wrote up a test script to make sure I was doing it properly. Here it is... code:$VAR1 is returning 577. If I'm not mistaken the operation should look something like this...BREAK ON code:Can someone shed some light on this for me?10-01000001 (577) Thanks, Ben [ 12. September 2002, 20:58: Message edited by: Ben Dulaney ] |
||||||||
|
|
|||||||
I have thought that too and shed some tears with it. but, I think the or is returning the first true value. can't test now (on linux machine), but what happens if you put it like: $VAR1 = 0 | &40 or like: $VAR1 = 1 | &40 just like and (&) checks if both are true...   |
||||||||
|
|
|||||||
$VAR1 = 0 | &40 returned 64 $VAR1 = 1 | &40 returned 65 I would expect these result based on my logic posted earlier. Do you agree? |
||||||||
|
|
|||||||
according your input, your first result (577 | 64) should have been: 641 I don't know... and as the [american]guru's aren't responding, I think you could ask this directly from ruud... you know, to get direct answer. then also let us know what he has to say. you cathced surely thing that has bothered me but I've been too lazy to ask about it. cheers.   |
||||||||
|
|
|||||||
Ben: OR sets a bit to 1 if either of the bits is 1 like code:Thus010 code:10-01000001 |
||||||||
|
|
|||||||
Apparantly I need an exclusive OR to do what I need to. I'm not aware of such a function in KiX. Is there anyway to get the result I'm looking for? Thanks, Ben |
||||||||
|
|
|||||||
Does code:get you where you need to go?$VAR1 = $Var1 - ($VAR1 & &40) [ 13. September 2002, 14:48: Message edited by: Howard Bullock ] |
||||||||
|
|
|||||||
That works when it is set to 577. However if I wanted to go from 513 back to 577 (turn the bit back on) that would not work. I need an operation that can flip-flop and flop-flip a bit in a binary number. Thanks, Ben [ 13. September 2002, 14:59: Message edited by: Ben Dulaney ] |
||||||||
|
|
|||||||
After a little creative thinking I think this may do the trick... code:Thanks for your input Howard. It put me on the road to binary bliss.BREAK ON This could be setup as a UDF code:Some method of checking $Bit to be sure it's a power of 2 would be good also.Function XOR($BinaryVal,$Bit) ;&BinaryVal = Value of binary number // $Bit = Value of bit to swap *UPDATE* I went ahead and decided to be proactive and added a routine to check the $Bit value. It's inlcuded in the above UDF. Thanks, Ben [ 13. September 2002, 15:49: Message edited by: Ben Dulaney ] |
||||||||
|
|
|||||||
Ben, I'd encourage you to write that function up and post it to the UDF forum. It will be harder to find if you just leave it in here. |
||||||||
|
|
|||||||
The above UDF has been posted to the UDF forum. I also made a few small changes to it. XOR() |
||||||||
|
|
|||||||
I've put XOR on the todo-list... ;-) Ruud |
||||||||
|
|
|||||||
Thanks, Ruud! |
||||||||
|
|
|||||||
Hi there, New on the forum! How's everybody doing? I'm looking for a way to set the "User cannot change password". I can't get the code in this topic to work, but I have something interesting: You al know the UserAccountControl option. With ADSI edit (Can be found in the support kit) you can view the value(Integer) of the UserAccountControl. With only one value set (Password never expires) the value = 66080. Changing the "User cannot change password option in de AD User and Computers value, the UserAccountControl value doensn't change. My conclusion is: You can't change the User Cannot Change Password option by setting the UserAccountControl. It must be ACL! Correct me if i'm totaly wrong please... Anyone more succes? |
||||||||
|
|
|||||||
You can set this flag. See my web page for a description of the bits of the flag and what they mean. http://home.comcast.net/~habullock/Win32Admin.htm#User Did you read the rest of the this thread? There is posted code that works using the WinNT:// ADSI provider. UserAccountControl would be used for LDAP and should also work. My guess is that you are not viewing the the same server with ADSIEDIT that you had changed. |