Sign in to follow this  
Followers 0
PsaltyDS

Ever wish you could set user properties...

2 posts in this topic

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:

; 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   ;==>_ComErrFunc

It 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... :whistle:


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

Share this post


Link to post
Share on other sites



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... :whistle:

; 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

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0