PsaltyDS Posted August 14, 2006 Posted August 14, 2006 I've been looking for the direct way to set "User cannot change password" and "Password never expires" on user accounts. I've been perusing MSDN on WinNT User Object, and the ADSI Enumerations of UserFlags.The following script contains a quick test (for which you would have to create "Test User" ahead of time) and my function to get, set, or clear bits in the user's UserFlags attributes:expandcollapse popup; Test of _UserCtrlAttribs() ; 14 August, 2006 - By PsaltyDS at http://www.autoitscript.com/forum ; Constants derived from: ; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/ads_user_flag_enum.asp Dim Const $USER_RUNSCRIPT = 0x1 ; User runs logon script. Dim Const $USER_ACCOUNTDISABLE = 0x2 ; User account disabled. Dim Const $USER_LOCKOUT = 0x10 ; Account is locked out. Dim Const $USER_NOPASSWD = 0x20 ; No password required. Dim Const $USER_NOCHANGEPASSWD = 0x40 ; User cannot change password. Dim Const $USER_NORMALACCOUNT = 0x200 ; Default account type of a normal user. Dim Const $USER_NOEXPIREPASSWD = 0x10000 ; Password will not expire. Dim Const $USER_SMARTCARDREQUIRED = 0x40000 ; Force user to log on using a smart card. Dim Const $USER_PASSWORDEXPIRED = 0x800000 ; Password has expired. ; Declare COM Object error handler: Global $oComError = ObjEvent("AutoIt.Error", "_ComErrFunc") $TstUsr = "Test User" ; User to work on $Result = _UserCtrlAttribs($TstUsr) MsgBox(64, "Results", "Initial UserFlags were: " & Hex($Result) & @CRLF & _ "@Error = " & @error) $NewBits = BitOR($USER_NOCHANGEPASSWD, $USER_NOEXPIREPASSWD) $Result = _UserCtrlAttribs($TstUsr, "Set", $NewBits) MsgBox(64, "Results", "Return from change was: " & Hex($Result) & @CRLF & _ "@Error = " & @error) $Result = _UserCtrlAttribs($TstUsr) MsgBox(64, "Results", "Final UserFlags are: " & Hex($Result) & @CRLF & _ "@Error = " & @error) ;-------------------------------------- ; Function _UserCtrlAttribs() ; Control attribute bits on a user account in the UserFlags word ; Call with: _UserCtrlAttribs($sUsrName, $sMode = "Get", $iAttribs = 0) where: ; $sUsrName = UserName to set attribute on ; $sMode = Action to take: ; "Get" (default) = Read the current UserFlags word without changing it ; "Set" = Set bit in UserFlags for each bit set in $iAttribs ; "Clear" = Clear bit in UserFlags for each bit set in $iAttribs ; $iAttribs = Attribute bits to set ; ; On success: Returns the resulting user account attributes flags. ; On failure: @error = 1 could not connect to user object ; @error = 2 invalid mode selected ; ; Note: If the context is not given for user or group, i.e. format is "UserName", ; then local computer context will be assumed. Domain or remote computer context ; can be provided by formatting user or group as "Context/UserName". ;-------------------------------------- Func _UserCtrlAttribs($sUsrName, $sMode = "Get", $iAttribs = 0) Local $iReturn = 0, $iErrors = 0 ; Format user for local if context not given Local $aUserSplit = StringSplit($sUsrName, "\/", 0) If $aUserSplit[0] = 1 Then $sUsrName = @ComputerName & "/" & $sUsrName Else $sUsrName = StringReplace($sUsrName, "\", "/") EndIf ; Init user COM object Local $objUser = ObjGet("WinNT://" & $sUsrName & ", User") If @error Or Not IsObj($objUser) Then Return SetError(1, 0, -1) ; Get current attributes $iCurrAttrib = $objUser.get ("UserFlags") If @error Then $iErrors += 1 Switch $sMode Case "Get" ; Return UserFlags $iReturn = $iCurrAttrib Case "Set" ; Set properties for user $iReturn = BitOR($iCurrAttrib, $iAttribs) $objUser.Put ("UserFlags", $iReturn) If @error Then $iErrors += 1 $objUser.SetInfo If @error Then $iErrors += 1 Case "Clear" ; Clear properties for user $iReturn = BitAND($iCurrAttrib, BitNOT($iAttribs)) $objUser.Put ("UserFlags", $iReturn) If @error Then $iErrors += 1 $objUser.SetInfo If @error Then $iErrors += 1 Case Else ; Invalid $sMode called Return SetError(2, 0, -1) EndSwitch ; Return results If $iErrors = 0 Then Return $iReturn Else Return SetError(1, 0, 0) EndIf EndFunc ;==>_UserCtrlAttribs ;-------------------------------------- ; Function _ComErrFunc() ; Custom COM object error handler ;-------------------------------------- Func _ComErrFunc() Local $HexNumber = Hex($oComError.number, 8) MsgBox(16, "COM ERROR!", "AutoIT COM Error Occured!" & @CRLF & _ @TAB & "Error Number: " & $HexNumber & @CRLF & _ @TAB & "Line Number: " & $oComError.scriptline & @CRLF & _ @TAB & "Description: " & $oComError.description & @CRLF & _ @TAB & "WinDescription: " & $oComError.windescription) SetError(1); something to check for when this function returns EndFunc ;==>_ComErrFuncIt seems to work in XP Pro SP2, and I'll test it on Windows 2003 Server tomorrow. Looking for more people to give it a try and see what might be improved... Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
PsaltyDS Posted August 15, 2006 Author Posted August 15, 2006 Updated the demo script to ask for the account, and have tested now on Windows 2003 server, with both local and AD domain accounts. So far, so good. The test now sets the following bits: $USER_ACCOUNTDISABLE, $USER_NOCHANGEPASSWD, and $USER_NOEXPIREPASSWD It then clears the bits for $USER_NOCHANGEPASSWD and $USER_NOEXPIREPASSWD, leaving the account disabled. Would still like to know if anyone sees something not working or easier some other way... expandcollapse popup; Test of _UserCtrlAttribs() ; 15 August, 2006 - By PsaltyDS at http://www.autoitscript.com/forum ; Constants derived from: ; http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adsi/adsi/ads_user_flag_enum.asp ; ===== General Account Flags ===== Dim Const $USER_RUNSCRIPT = 0x1 ; User runs logon script. Dim Const $USER_ACCOUNTDISABLE = 0x2 ; User account disabled. Dim Const $USER_LOCKOUT = 0x10 ; Account is locked out. Dim Const $USER_NOPASSWD = 0x20 ; No password required. Dim Const $USER_NOCHANGEPASSWD = 0x40 ; User cannot change password. Dim Const $USER_NORMALACCOUNT = 0x200 ; Default account type of a normal user. Dim Const $USER_NOEXPIREPASSWD = 0x10000 ; Password will not expire. Dim Const $USER_SMARTCARDREQUIRED = 0x40000 ; Force user to log on using a smart card. Dim Const $USER_PASSWORDEXPIRED = 0x800000 ; Password has expired. ; Declare COM Object error handler: Global $oComError = ObjEvent("AutoIt.Error", "_ComErrFunc") $TstUsr = InputBox("_UserCtrlAttribs() Demo", "Input user name to change: ", "") ; Get user to work on If $TstUsr = "" Then Exit $Result = _UserCtrlAttribs($TstUsr) MsgBox(64, "Results", "Initial UserFlags were: " & Hex($Result) & @CRLF & _ "@Error = " & @error) $NewBits = BitOR($USER_NOCHANGEPASSWD, $USER_NOEXPIREPASSWD, $USER_ACCOUNTDISABLE) $Result = _UserCtrlAttribs($TstUsr, "Set", $NewBits) $Result = _UserCtrlAttribs($TstUsr) MsgBox(64, "Results", "UserFlags after setting bits are: " & Hex($Result) & @CRLF & _ "@Error = " & @error) $NewBits = BitOR($USER_NOCHANGEPASSWD, $USER_NOEXPIREPASSWD) $Result = _UserCtrlAttribs($TstUsr, "Clear", $NewBits) $Result = _UserCtrlAttribs($TstUsr) MsgBox(64, "Results", "UserFlags after clearing bits are: " & Hex($Result) & @CRLF & _ "@Error = " & @error) ;-------------------------------------- ; Function _UserCtrlAttribs() ; Control attribute bits on a user account in the UserFlags word ; Call with: _UserCtrlAttribs($sUsrName, $sMode = "Get", $iAttribs = 0) where: ; $sUsrName = UserName to set attribute on ; $sMode = Action to take: ; "Get" (default) = Read the current UserFlags word without changing it ; "Set" = Set bit in UserFlags for each bit set in $iAttribs ; "Clear" = Clear bit in UserFlags for each bit set in $iAttribs ; $iAttribs = Attribute bits to set ; ; On success: Returns the resulting user account attributes flags. ; On failure: @error = 1 could not connect to user object ; @error = 2 invalid mode selected ; ; Note: If the context is not given for user or group, i.e. format is "UserName", ; then local computer context will be assumed. Domain or remote computer context ; can be provided by formatting user or group as "Context/UserName". ;-------------------------------------- Func _UserCtrlAttribs($sUsrName, $sMode = "Get", $iAttribs = 0) Local $iReturn = 0, $iErrors = 0 ; Format user for local if context not given Local $aUserSplit = StringSplit($sUsrName, "\/", 0) If $aUserSplit[0] = 1 Then $sUsrName = @ComputerName & "/" & $sUsrName Else $sUsrName = StringReplace($sUsrName, "\", "/") EndIf ; Init user COM object Local $objUser = ObjGet("WinNT://" & $sUsrName & ", User") If @error Or Not IsObj($objUser) Then Return SetError(1, 0, -1) ; Get current attributes $iCurrAttrib = $objUser.get ("UserFlags") If @error Then $iErrors += 1 Switch $sMode Case "Get" ; Return UserFlags $iReturn = $iCurrAttrib Case "Set" ; Set properties for user $iReturn = BitOR($iCurrAttrib, $iAttribs) $objUser.Put ("UserFlags", $iReturn) If @error Then $iErrors += 1 $objUser.SetInfo If @error Then $iErrors += 1 Case "Clear" ; Clear properties for user $iReturn = BitAND($iCurrAttrib, BitNOT($iAttribs)) $objUser.Put ("UserFlags", $iReturn) If @error Then $iErrors += 1 $objUser.SetInfo If @error Then $iErrors += 1 Case Else ; Invalid $sMode called Return SetError(2, 0, -1) EndSwitch ; Return results If $iErrors = 0 Then Return $iReturn Else Return SetError(1, 0, 0) EndIf EndFunc ;==>_UserCtrlAttribs ;-------------------------------------- ; Function _ComErrFunc() ; Custom COM object error handler ;-------------------------------------- Func _ComErrFunc() Local $HexNumber = Hex($oComError.number, 8) MsgBox(16, "COM ERROR!", "AutoIT COM Error Occured!" & @CRLF & _ @TAB & "Error Number: " & $HexNumber & @CRLF & _ @TAB & "Line Number: " & $oComError.scriptline & @CRLF & _ @TAB & "Description: " & $oComError.description & @CRLF & _ @TAB & "WinDescription: " & $oComError.windescription) SetError(1); something to check for when this function returns EndFunc ;==>_ComErrFunc Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now