JeffS
(Fresh Scripter)
2009-03-14 12:11 AM
User Account Locked Notification

So I was assigned the task to figure out a way to send an email notification when a user account has been locked out in an economical fashion (please read as free).

I thought that I could go with an Event Viewer reader and some how parse out all of the Event IDs from each domain controller and then figure out a way to send an email notification out from there. Not really feasible.

Thus I found this nifty utility: Unlock Utility

 Code:
unlock.exe . * -view


By running the command above I can get a list of domain accounts who are currently locked out.

If an account is found to be locked out it will appear as follows:
 Code:
 1: [i]username[/i]03/13/2009-15:09:38 LOCKED   VIEW_ONLY 


If not accounts are found it shows the following:
 Code:
No Objects Found 


So now I want to figure out a way to "automate" this. I know that since this is a free solution there is no way to "instantly automate" it. However, here are my thoughts:

Create the script and assign it as a schedule task to run every minute. If a locked account(s) are found have it copy that portion to the body of an email and send it using blat or some other email utility. If "No Objects Found" is returned then end the script and close it (no email sent).

I have the idea of how it would work, I am just having issues executing it. Seeing that I haven't had to touch a KiX script in over a year my skills and knowledge are seriously lacking. Thus I turn to the experts, you guys! \:\)

Any help is appreciated! Thanks a bunch!


Glenn BarnasAdministrator
(KiX Supporter)
2009-03-14 12:23 AM
Re: User Account Locked Notification

It just so happens that I have a script that runs every Monday morning that checks for expired, locked, and about-to-expire accounts. It generates a report and emails the report to specific users. Since this does 173% of what you need, I've posted it here and you can remove the unwanted parts and customize it to your specific needs..

The core pieces are there - look for accounts that are locked, send email. \:\)

Glenn

;; KixGenerated: 2008/10/22 10:00:32 
Break On
 
Dim $Members, $Member			; array of domain user members, enumerator var 
Dim $I					; index var 
Dim $objUser				; AD user query object pointer 
Dim $Flags				; user flags 
Dim $ExpDate, $Days			; expiration date, days remaining 
Dim $LStat, $EStat			; locked and Expired status flags 
Dim $RptData[0], $R			; report array, record pointer 
Dim $Header				; report page header 
Dim $MaxDays				; max days before expiration 
Dim $MailTo, $MailSender, $MailServer	; mail parameters 
Dim $BlatCmd				; Blat command string 
 
$MaxDays = 10				; passwords expiring within 10 days 
 
; get array of user accounts 
'Collecting'
$Members = GroupMembers(@DOMAIN, 'Domain Users', 2)
Chr(13) 'Reporting ' ?
 
$R = -1
 
; header 
;00000000011111111112222222222333333333344444444445555555555666666666677777777778 
;12345678901234567890123456789012345678901234567890123456789012345678901234567890 
$Header = 'UserID         UserName                                Locked? Expired?' + @CRLF
$Header = $Header + '  Expiration date' + @CRLF
$Header = $Header + '===============================================================================' + @CRLF
 
For Each $Member In $Members
 
  ; get specific user data 
  $objUser = GetObject('WinNT://' + @DOMAIN + '/' +$Member + ',user')
 
  ; read flags 
  $Flags = $objUser.UserFlags 
 
  ; if not disabled, and not Never Expires, report on expired or about to expire accounts 
  If Not $objUser.AccountDisabled And Not ($Flags & 65536)
    $ExpDate = FixDate($objUser.PasswordExpirationDate)
    $Days = Int(TimeDiff('Now', $ExpDate, 'D'))
    $LStat = $objUser.IsAccountLocked
    $EStat = $objUser.PasswordExpired
    If $EStat Or $LStat Or $Days < 10
      $R = $R + 1
      ReDim Preserve $RptData[$R]
      $RptData[$R] = Left($Member + '                    ', 15)
      $RptData[$R] = $RptData[$R] + Left($objUser.FullName + '                                        ', 40)
 
      ; display LOCKED and EXPIRED status 
      If $LStat
        $RptData[$R] = $RptData[$R] + 'LOCKED  '
      Else
        $RptData[$R] = $RptData[$R] + '        '
      EndIf
      If $EStat
        $RptData[$R] = $RptData[$R] + 'EXPIRED   ' + @CRLF + '   ' + $ExpDate
      Else
        ; get remaining days 
        If $Days < $MaxDays
          $RptData[$R] = $RptData[$R] + $Days + ' REMAIN  ' + @CRLF + '   ' + $ExpDate
        Else
          $RptData[$R] = $RptData[$R] + '          '
        EndIf
      EndIf
      If Exist('.\debug.txt')
        $RptData[$R] ?
        $I = $I + 1
        If $I > 100 Quit 0 EndIf
      EndIf
    EndIf
  EndIf
 
Next
 
Del '%S_CONFIG%\Logs\ExpiredPW.txt'				; remove prior report 
$R = RedirectOutput('%S_CONFIG%\Logs\ExpiredPW.txt')		; create new report file 
$Header						; output the header 
For $R = 0 to UBound($RptData)
  If $R Mod 52 = 0 And $R > 0
    Chr(12) $Header				; output a formfeed and header every 52 records 
  EndIf
  $RptData[$R] ?
Next
$R = RedirectOutput('')				; close the report file 
 
$MailTo     = ReadProfileString('%S_CONFIG%\lockout.ini', 'MAIL', 'MailTo')
$MailSender = ReadProfileString('%S_CONFIG%\lockout.ini', 'MAIL', 'MailSender')
$MailServer = ReadProfileString('%S_CONFIG%\lockout.ini', 'MAIL', 'MailServer')
 
; send the report via email (BLAT) 
If $MailTo <> ''
  $BlatCmd = '%COMSPEC% /c %S_BIN%\blat.exe %S_CONFIG%\Logs\ExpiredPW.txt'
  $BlatCmd = $BlatCmd + ' -to ' + $MailTo
  $BlatCmd = $BlatCmd + ' -subject "Expiring Passwords"'
  $BlatCmd = $BlatCmd + ' -f ' + $MailSender
  $BlatCmd = $BlatCmd + ' -server ' + $MailServer
  $BlatCmd = $BlatCmd + ' >NUL:'
  Shell $BlatCmd
EndIf
 
Exit 0
 
 
; ================================================================================ 
; correct the date format - change from "11/1/2007 2:31:30 PM" to "2007/11/01 14:31:30" 
Function FixDate($_Date)
 
  Dim $_ODate
  Dim $_Tmp
  $_ODate = Split($_Date, ' ')
 
  ; Change the date format 
  $_Tmp = Split($_ODate[0], '/')
  $_ODate[0] = $_Tmp[2] + '/' + Right('0' + $_Tmp[0], 2) + '/' + Right('0' + $_Tmp[1], 2)
 
  ; Change the time format 
  $_Tmp = Split($_ODate[1], ':')
  If $_ODate[2] = 'PM' And Val($_Tmp[0]) < 12
    $_Tmp[0] = Right('0' + (Val($_Tmp[0]) + 12), 2)
  Else
    $_Tmp[0] = Right('0' + $_Tmp[0], 2)
  EndIf
  $_ODate[1] = Join($_Tmp, ':')
 
  $FixDate = $_ODate[0] + ' ' + $_ODate[1]
  Exit 0
 
EndFunction
 
 
 
; 
;FUNCTION    GroupMembers 
; 
;ACTION      Returns an array of all group members of the specified group 
; 
;SYNTAX      GroupMembers(Target, Group, [FLAG]) 
; 
;PARAMETERS  Target 
;               The Domain name or Workstation to work with.  For faster workstation  
;               execution, include the Domain Name that the workstation is a meber of. 
; 
;               "Kixtart/beanbag" would be working with the workstation Beanbag in the  
;               Kixtart domain 
; 
;            Group 
;               The Group you want to query 
; 
;            [FLAGS] 
;               To use the flags options add the numbers of the desired flags toghthers and 
;               Use that number in the flag field. 
; 
;                  Filter :(only one filter flag at a time please) 
;                     1 = all 
;                     2 = Users only 
;                     4 = Groups only 
; 
;                  ADSI Information(return ADSI information "pick only one") 
;                     8  = ADSPath field 
;                     16 = ADSI Object Handle 
; 
;RETURNS     an array containing , if the ADSPath option is used the ADSPath  
;            will also be returned |. 
; 
;REMARKS     ADSI com object must be installed. 
; 
;EXAMPLES    ;this return all members of the Domain Admins group in the kixtart domain. 
;            $members = groupmembers("kixtart","Domain admins") 
; 
;            ;this will will return all groups in the local administrators group on  
;            ;the Workstation beanbad in the kixtart domain.  Also the  
;            $groups = groupmembers("kixtart/beanbag","Administratoos","group") 
Function Groupmembers($target, $group, optional $flag)
 
  DIM $temparray[8], $member, $i, $chunk, $flag, $ADSIFlag, $filterFlag
 
  $chunk = ubound($temparray)
  $flag = val($flag)
  $i = 0
  $group = getobject("WinNT://" + $target + "/" + $group)
 
  if vartype($group) <> 9 exit(@error) endif
 
  select
    case $flag & 1
      $filterflag = 1
    case $flag & 2
      $filterflag = 2
    case $flag & 4
      $filterflag = 4
    case 1
      $filterflag = 1
  endselect
 
  select
    case $flag & 8
      $ADSIFlag = 8
    case $flag & 16
      $ADSIFlag = 16
  endselect
 
  for each $member in $group.members
    select
      case $filterflag = 2 AND $member.class = "user"
        if substr($member.name,len($member.name),1) <> Chr(36)
          $temparray[$i] = $member.name
 
          select
            case $adsiflag = 8
              $temparray[$i] = $member.adspath
 
            case $adsiflag = 16
              $temparray[$i] = $member
 
          endselect
 
          $i = $i + 1
 
        endif
 
      case $filterflag = 4 AND $member.class = "Group"
        if substr($member.name,len($member.name),1) <> Chr(36)
          $temparray[$i] = $member.name
 
          select
            case $adsiflag = 8
              $temparray[$i] = $member.adspath
 
            case $adsiflag = 16
              $temparray[$i] = $member
 
          endselect
 
          $i = $i + 1
 
        endif
 
      case $filterflag = 1
        if substr($member.name,len($member.name),1) <> Chr(36)
          $temparray[$i] = $member.name
 
          select
            case $adsiflag = 8
              $temparray[$i] = $member.adspath
 
            case $adsiflag = 16
              $temparray[$i] = $member
 
          endselect
 
          $i = $i + 1
 
        endif
 
      case $filterflag
        ;bit bucket 
 
    endselect
 
    if $i = ubound($temparray)
      redim preserve $temparray[Ubound($temparray)+$chunk]
 
    endif
 
  next
 
  if $i <> 0
    redim preserve $temparray[$i-1]
    $groupmembers=$temparray
 
  endif
 
endfunction
 
;; 
;;====================================================================== 
;; 
;;FUNCTION       TimeDiff() 
;; 
;;AUTHOR         Glenn Barnas 
;; 
;;VERSION        2.2 / 2007/10/14 
;;		 Modified to increase accuracy, permit fracional second calculations 
;;		 2.1 / 2007/03/17 
;;               added "now" and "today" options for both start and end times 
;;               2.0 / 2006/11/20 
;;               Changes for code efficiency; added defaults for midnight  
;; 
;;ACTION         Calculates the time difference between two given date/time strings 
;; 
;;SYNTAX         TimeDiff(Start [, End] [, Format] [, MSec]) 
;; 
;;PARAMETERS     Start  - REQUIRED, String value representing the start timestamp 
;;                 Format yyyy/mm/dd hh:mm:ss 
;; 
;;               End    - OPTIONAL, Defaults to "now" 
;;		   String value representing the ending time 
;;                 Format yyyy/mm/dd hh:mm:ss 
;;		   Can be the special value "now" for the current date/time, or "today" 
;;                 for midnight of the current day. 
;; 
;;                 When the time value is not specified, it defaults to 00:00:00.000 (midnight) 
;; 
;;		 Format - OPTIONAL, one of: 
;;		  "m" - return minutes 
;;		  "h" - return hours 
;;		  "d" - return days 
;;		  "y" - return years 
;;		 When a format value is specified, it returns the fractional part (ie 0.5 days for 12 hours). 
;; 
;;		 MSec	- OPTIONAL, True if the fractional seconds should be returned. Default 
;;		  is false, returning whole seconds, to maintain compatibility with earlier versions. 
;;		  MSec only affects the return of fractional seconds, not fractional parts of other time formats. 
;; 
;;REMARKS        Returns a value representing the difference in time between two date/time 
;;		 strings. Assumes that "Start" is in the past, but will properly return a 
;;		 negative value if it is in the future. 
;; 
;;RETURNS        Double - difference between Start and End timestamps in seconds 
;; 
;;DEPENDENCIES   None 
;; 
;;TESTED WITH    Kix 4.2+, NT4, W2K, WXP, W2K3 
;; 
;;EXAMPLES       If TimeDiff(GetFileTime('SomeFile.txt'),  'now', 'h') > 48 
;;		   "File is more than 2 days old!" ? 
;;		 EndIf 
; 
Function TimeDiff($_Start, OPTIONAL $_End, OPTIONAL $_Fmt, OPTIONAL $_MSec)
 
  Dim $_, $_SDate, $a_Start, $_EDate, $a_End, $_Duration
 
  ; Check for special START parameters 
  Select
   Case $_Start = 'now'
    $_Start = @DATE + ' ' + @TIME + '.' + @MSECS
   Case $_START = 'today'
    $_Start = @DATE + ' 00:00:00.000'
  EndSelect
 
  ; Check for special END parameters 
  Select
   Case $_End = 'now' Or $_End = '' 
    $_End = @DATE + ' ' + @TIME + '.' + @MSECS
   Case $_End = 'today'
    $_End = @DATE + ' 00:00:00.000'
  EndSelect
 
  ; Validate parameters 
  ; Parameters passed are "yyyy/mm/dd hh:mm:ss[.sss]" - make sure the default time is added 
  $a_Start = Split(Join(Split(Join(Split($_Start + ' 00:00:00.000', '/'), ' '), ':'), ' '), ' ', 6)
  If UBound($a_Start) <> 5 Exit 87 EndIf		; bad start time parameter 
  For $_ = 0 to 5
    $a_Start[$_] = CDbl($a_Start[$_])		; convert to numeric values 
  Next
 
  $a_End = Split(Join(Split(Join(Split($_End + ' 00:00:00.000', '/'), ' '), ':'), ' '), ' ', 6)
  If UBound($a_End) <> 5 Exit 87 EndIf		; bad start time parameter 
  For $_ = 0 to 5
    $a_End[$_] = CDbl($a_End[$_])		; convert to numeric values 
  Next
 
  ; Convert dates to Days, then convert to seconds and add the time value 
  If $a_Start[1] < 3
    $a_Start[1] = $a_Start[1] + 12
    $a_Start[0] = $a_Start[0] - 1
  EndIf
  $_SDate = $a_Start[2] + ( 153 * $a_Start[1] - 457 ) / 5 + 365 * $a_Start[0] + $a_Start[0] / 4 - $a_Start[0] / 100 + $a_Start[0] / 400 - 306
  $_SDate = CDbl($_SDate) * 86400.0
  $_SDate = $_SDate + $a_Start[3] * 3600 + $a_Start[4] * 60 + $a_Start[5]
 
  If $a_End[1] < 3
    $a_End[1] = $a_End[1] + 12
    $a_End[0] = $a_End[0] - 1
  EndIf
  $_EDate = $a_End[2] + ( 153 * $a_End[1] - 457 ) / 5 + 365 * $a_End[0] + $a_End[0] / 4 - $a_End[0] / 100 + $a_End[0] / 400 - 306
  $_EDate = CDbl($_EDate) * 86400.0
  $_EDate = $_EDate + $a_End[3] * 3600 + $a_End[4] * 60 + $a_End[5]
 
  ; Get the duration between the timestamps 
  $_Duration = CDbl($_EDate - $_SDate)
 
  ; Trim fractional seconds if the MSec flag wasn't set 
  ; Value returned is whole seconds 
  If Not $_MSec
    $_Duration = CInt($_Duration)
  EndIf
 
  ; Return data as a Double - seconds (default), hours, minutes, days, or years 
  Select
    Case $_Fmt = 'm'	; minutes 
      $TimeDiff = $_Duration / 60.0
    Case $_Fmt = 'h'	; hours 
      $TimeDiff = $_Duration / 3600.0
    Case $_Fmt = 'd'	; days 
      $TimeDiff = $_Duration / 86400.0
    Case $_Fmt = 'y'	; years 
      $TimeDiff = $_Duration / 31536000.0
    Case 1
      $TimeDiff = $_Duration
  EndSelect
 
  Exit 0
 
EndFunction
 
 
 
 
 


Glenn BarnasAdministrator
(KiX Supporter)
2009-03-14 12:26 AM
Re: User Account Locked Notification

Couple of quick notes. You need blat.exe to send mail with this script. The S_BIN and S_CONFIG are environment variables that define (to my scripts) where other binary tools and script are (S_BIN) and config files can be found (S_CONFIG). You can easily replace that with @SCRIPTDIR, but I personally find that messy..

I create C:\Local to hold all my config files for all scripts. I create C:\Local\Bin for any executables and scripts. This way, everything is in one logical place, and one script can use another easily.

Glenn


JeffS
(Fresh Scripter)
2009-03-14 12:27 AM
Re: User Account Locked Notification

Awesome, thanks!

Glenn BarnasAdministrator
(KiX Supporter)
2009-03-14 12:29 AM
Re: User Account Locked Notification

No problem.. I don't usually do silver platter code, but this took no effort, and you'll need to do some tweaking to this to meet your needs... post your results back to share when you get it working.

Glenn


NTDOCAdministrator
(KiX Master)
2009-03-14 02:51 AM
Re: User Account Locked Notification

My gosh... how long are you guys locking accounts that you have to send mail?

Gargoyle
(MM club member)
2009-03-14 03:41 AM
Re: User Account Locked Notification

@Doc,
In the infinite wisdom of the powers that be at my place employ, they mandated that there is "NO" timeout on locked accounts.

Why I still have not fathomed.


Glenn BarnasAdministrator
(KiX Supporter)
2009-03-15 03:07 AM
Re: User Account Locked Notification

Don't you work for some Govt agency? Doesn't "no timeout" result in a permanant lock on the account until manually unlocked?

When I was at the Fed, we had a similar policy - lockout was permanent until someone validated your identity (you know, the "what was your brother's wife's cousin's pet's name when she was in second grade" question.) Once a human being could confirm your answer, they would unlock your account. Often, there were two or three such questions that were asked.

I imagine that most companies with a staffed operations center and dealing with financial or other sensitive data would have similar rules.

Glenn


LonkeroAdministrator
(KiX Master Guru)
2009-03-15 03:22 AM
Re: User Account Locked Notification

for my questions the right answer would always be: "how the heck could I remember that?"

Gargoyle
(MM club member)
2009-03-15 08:24 AM
Re: User Account Locked Notification

@Glenn - You are correct and it is Hipaa requirements.

@Lonk - Join the club \:\)


NTDOCAdministrator
(KiX Master)
2009-03-16 07:55 AM
Re: User Account Locked Notification

Even at the Mouse who was rather paranoid about security, they only locked it out for 15 minutes. The whole point of a lock out is to help prevent HACKING the account, not prevent the user with a slow memory on Monday from doing their job. Yeah I suppose a permanent lockout would help on the hacking part but then goes against the other part which is more often than not the reason for the lock in the first place.

JeffS
(Fresh Scripter)
2009-03-16 05:46 PM
Re: User Account Locked Notification

 Originally Posted By: NTDOC
My gosh... how long are you guys locking accounts that you have to send mail?


I work at a financial institution and for us, once you are locked out you better hope you know the Helpdesk's extension because you aren't getting back in until you call them.


NTDOCAdministrator
(KiX Master)
2009-03-16 06:19 PM
Re: User Account Locked Notification

Oh I see that based on at least a couple responses here and the desire to create code around it.

I'm just saying that I think Management or someone else is/was in charge of setting that lockout duration. Maybe you're Company is somehow under attack from hacking tools or users inside (often the case that an insider is the one doing the attack than outsider) and that is the reason for having a lockout so that you can't automate a tool against an account in that manner (there or other methods). But in a very large network of 140K desktops and 4K+ Servers we never had an account cracked on NT that we were aware of. Yes we have caught people inside using tools to attack accounts (again a reasonable lockout duration puts a big damper on that). We also found Admins copying the security databases and trying to crack them (no duration lockout will thwart that). We did have all types of attacks "attempted" from outside but none of them hacked a NT account. We did have a couple of FTP accounts on Linux hacked though one of which also lead to root take over. On a different subject - Web attacks on Windows boxes have been more successful than most other methods.

So I still have to ask WHY!!! I just see it as adding a layer of un-needed support on one end to open it back up, and also creating a non productive user for anywhere from an hour to a day or more???

My view is that we as IT Professionals are here to ENABLE users not CONTROL users.


JeffS
(Fresh Scripter)
2009-03-16 10:02 PM
Re: User Account Locked Notification

 Code:
; read flags 
  $Flags = $objUser.UserFlags 
 
  ; if not disabled, and not Never Expires, report on expired or about to expire accounts 
  If Not $objUser.AccountDisabled And Not ($Flags & 65536)
    $ExpDate = FixDate($objUser.PasswordExpirationDate)
    $Days = Int(TimeDiff('Now', $ExpDate, 'D'))
    $LStat = $objUser.IsAccountLocked
    $EStat = $objUser.PasswordExpired
    If $EStat Or $LStat Or $Days < 10
      $R = $R + 1
      ReDim Preserve $RptData[$R]
      $RptData[$R] = Left($Member + '                    ', 15)
      $RptData[$R] = $RptData[$R] + Left($objUser.FullName + '                                        ', 40)
 
      ; display LOCKED and EXPIRED status 
      If $LStat
        $RptData[$R] = $RptData[$R] + 'LOCKED  '
      Else
        $RptData[$R] = $RptData[$R] + '        '
      EndIf
      If $EStat
        $RptData[$R] = $RptData[$R] + 'EXPIRED   ' + @CRLF + '   ' + $ExpDate
      Else
        ; get remaining days 
        If $Days < $MaxDays
          $RptData[$R] = $RptData[$R] + $Days + ' REMAIN  ' + @CRLF + '   ' + $ExpDate
        Else
          $RptData[$R] = $RptData[$R] + '          '
        EndIf
      EndIf
      If Exist('.\debug.txt')
        $RptData[$R] ?
        $I = $I + 1
        If $I > 100 Quit 0 EndIf
      EndIf
    EndIf
  EndIf


I ran the full report as pasted into the forum. However, I was looking at the expired accounts and some of them have a date set out in the future, some as far as June this year. What is that date? Or is there an issue with he way the script converts the time of a previous year?


JeffS
(Fresh Scripter)
2009-03-16 10:11 PM
Re: User Account Locked Notification

 Originally Posted By: NTDOC
Oh I see that based on at least a couple responses here and the desire to create code around it.

I'm just saying that I think Management or someone else is/was in charge of setting that lockout duration. Maybe you're Company is somehow under attack from hacking tools or users inside (often the case that an insider is the one doing the attack than outsider) and that is the reason for having a lockout so that you can't automate a tool against an account in that manner (there or other methods). But in a very large network of 140K desktops and 4K+ Servers we never had an account cracked on NT that we were aware of. Yes we have caught people inside using tools to attack accounts (again a reasonable lockout duration puts a big damper on that). We also found Admins copying the security databases and trying to crack them (no duration lockout will thwart that). We did have all types of attacks "attempted" from outside but none of them hacked a NT account. We did have a couple of FTP accounts on Linux hacked though one of which also lead to root take over. On a different subject - Web attacks on Windows boxes have been more successful than most other methods.

So I still have to ask WHY!!! I just see it as adding a layer of un-needed support on one end to open it back up, and also creating a non productive user for anywhere from an hour to a day or more???

My view is that we as IT Professionals are here to ENABLE users not CONTROL users.


I am currently working at my second financial institutions as an Admin and in both settings, there has no been a setting to unlock the account after a certain time period. The user HAS to call in to get their account unlocked.

Both places I have screamed until I am blue in the face about this, it is probably costing you more in salary and productivity not to set this setting. Think about it, the productivity lost of the user who is locked out and also the productivity the helpdesk user taking the call and from other issues.

I believe Management sees this as another potential way to safe guard and potentially save a buck. By having users call in to get unlocked they can potentially skip other costs somewhere else. Maybe cheaper security equipment, etc.

To me, you should either set the setting to allow it to unlock after a certain amount of time or to purchase a product where the user can unlock themselves.


NTDOCAdministrator
(KiX Master)
2009-03-17 01:32 AM
Re: User Account Locked Notification

Do these accounts have their password set to NEVER expire?

JeffS
(Fresh Scripter)
2009-03-17 05:40 PM
Re: User Account Locked Notification

 Originally Posted By: NTDOC
Do these accounts have their password set to NEVER expire?


Nope, the only "flag" that the user account has is that it must change its password at next logon.


NTDOCAdministrator
(KiX Master)
2009-03-17 06:40 PM
Re: User Account Locked Notification

What the actual account expiration? Is the account set to never expire or set to expire some time in the near future?

Just trying to determine what is different about the account compared to others that don't return that result. Something has to be a bit different.


Glenn BarnasAdministrator
(KiX Supporter)
2009-03-17 08:40 PM
Re: User Account Locked Notification

To answer the original question, the expiration date you're seeing is when the password "would" expire if you had an expiration policy in place. If it's 4 months out, it would seem that a policy somewhere was set at one time to 120 days or so. That is also why you may see accounts that have expire dates in the past, but aren't affected because they have an "account never expires" setting.

Glenn


JeffS
(Fresh Scripter)
2009-03-30 07:32 PM
Re: User Account Locked Notification

Modified the script, however I am having an issue. Even when the account is locked it reports it is NOTLOCKED. I am obviously missing something somewhere but I am stumped. Any help?

 Code:
;; KixGenerated: 2008/10/22 10:00:32 
Break On
 
Dim $Members, $Member			; array of domain user members, enumerator var 
Dim $I					; index var 
Dim $objUser				; AD user query object pointer 
Dim $Flags				; user flags 
Dim $LStat				; locked status flags 
Dim $RptData[0], $R			; report array, record pointer 
Dim $Header				; report page header 
Dim $MailTo, $MailSender, $MailServer	; mail parameters 
Dim $BlatCmd				; Blat command string 
 
; get array of user accounts 
'Collecting'
$Members = GroupMembers(@DOMAIN, 'Domain Users', 2)
Chr(13) 'Reporting ' ?
 
$R = -1
 
; header 
;00000000011111111112222222222333333333344444444445555555555666666666677777777778 
;12345678901234567890123456789012345678901234567890123456789012345678901234567890 
$Header = 'UserID         UserName                                Locked? Expired?' + @CRLF
$Header = $Header + '  Expiration date' + @CRLF
$Header = $Header + '===============================================================================' + @CRLF

For Each $Member In $Members
 
  ; get specific user data 
  $objUser = GetObject('WinNT://' + @DOMAIN + '/' +$Member + ',user')
 
$LStat = $objUser.IsAccountLocked

If $LStat = TRUE
  $R = $R + 1
  ReDim Preserve $RptData[$R]
  $RptData[$R] = Left($Member + '                    ', 15)
  $RptData[$R] = $RptData[$R] + Left($objUser.FullName + '                                        ', 40)
  If $LStat  
    $RptData[$R] = $RptData[$R] + 'LOCKED'
  Else 
    $RptData[$R] = $RptData[$R] + 'NOTLOCKED'
  EndIf
  If Exist('.\debug.txt')
    $RptData[$R] ?
    $I = $I + 1
    If 
     $I > 100 Quit 0 
   EndIf
  EndIf
 EndIf
Next

    

Del '%S_CONFIG%\Logs\Locked.txt'				; remove prior report 
$R = RedirectOutput('%S_CONFIG%\Logs\Locked.txt')		; create new report file 
$Header						; output the header 
For $R = 0 to UBound($RptData)
  If $R Mod 52 = 0 And $R > 0
    Chr(12) $Header				; output a formfeed and header every 52 records 
  EndIf
  $RptData[$R] ?
Next
$R = RedirectOutput('')				; close the report file 
 
$MailTo     = ReadProfileString('%S_CONFIG%\lockout.ini', 'MAIL', 'MailTo')
$MailSender = ReadProfileString('%S_CONFIG%\lockout.ini', 'MAIL', 'MailSender')
$MailServer = ReadProfileString('%S_CONFIG%\lockout.ini', 'MAIL', 'MailServer')
 
; send the report via email (BLAT) 
If $MailTo <> ''
  $BlatCmd = '%COMSPEC% /c %S_BIN%\Blat\blat.exe %S_CONFIG%\Logs\Locked.txt'
  $BlatCmd = $BlatCmd + ' -to ' + $MailTo
  $BlatCmd = $BlatCmd + ' -subject "Expiring Passwords"'
  $BlatCmd = $BlatCmd + ' -f ' + $MailSender
  $BlatCmd = $BlatCmd + ' -server ' + $MailServer
  $BlatCmd = $BlatCmd + ' >NUL:'
  Shell $BlatCmd
EndIf
 
Exit 0

; 
;FUNCTION    GroupMembers 
; 
;ACTION      Returns an array of all group members of the specified group 
; 
;SYNTAX      GroupMembers(Target, Group, [FLAG]) 
; 
;PARAMETERS  Target 
;               The Domain name or Workstation to work with.  For faster workstation  
;               execution, include the Domain Name that the workstation is a meber of. 
; 
;               "Kixtart/beanbag" would be working with the workstation Beanbag in the  
;               Kixtart domain 
; 
;            Group 
;               The Group you want to query 
; 
;            [FLAGS] 
;               To use the flags options add the numbers of the desired flags toghthers and 
;               Use that number in the flag field. 
; 
;                  Filter :(only one filter flag at a time please) 
;                     1 = all 
;                     2 = Users only 
;                     4 = Groups only 
; 
;                  ADSI Information(return ADSI information "pick only one") 
;                     8  = ADSPath field 
;                     16 = ADSI Object Handle 
; 
;RETURNS     an array containing , if the ADSPath option is used the ADSPath  
;            will also be returned |. 
; 
;REMARKS     ADSI com object must be installed. 
; 
;EXAMPLES    ;this return all members of the Domain Admins group in the kixtart domain. 
;            $members = groupmembers("kixtart","Domain admins") 
; 
;            ;this will will return all groups in the local administrators group on  
;            ;the Workstation beanbad in the kixtart domain.  Also the  
;            $groups = groupmembers("kixtart/beanbag","Administratoos","group") 
Function Groupmembers($target, $group, optional $flag)
 
  DIM $temparray[8], $member, $i, $chunk, $flag, $ADSIFlag, $filterFlag
 
  $chunk = ubound($temparray)
  $flag = val($flag)
  $i = 0
  $group = getobject("WinNT://" + $target + "/" + $group)
 
  if vartype($group) <> 9 exit(@error) endif
 
  select
    case $flag & 1
      $filterflag = 1
    case $flag & 2
      $filterflag = 2
    case $flag & 4
      $filterflag = 4
    case 1
      $filterflag = 1
  endselect
 
  select
    case $flag & 8
      $ADSIFlag = 8
    case $flag & 16
      $ADSIFlag = 16
  endselect
 
  for each $member in $group.members
    select
      case $filterflag = 2 AND $member.class = "user"
        if substr($member.name,len($member.name),1) <> Chr(36)
          $temparray[$i] = $member.name
 
          select
            case $adsiflag = 8
              $temparray[$i] = $member.adspath
 
            case $adsiflag = 16
              $temparray[$i] = $member
 
          endselect
 
          $i = $i + 1
 
        endif
 
      case $filterflag = 4 AND $member.class = "Group"
        if substr($member.name,len($member.name),1) <> Chr(36)
          $temparray[$i] = $member.name
 
          select
            case $adsiflag = 8
              $temparray[$i] = $member.adspath
 
            case $adsiflag = 16
              $temparray[$i] = $member
 
          endselect
 
          $i = $i + 1
 
        endif
 
      case $filterflag = 1
        if substr($member.name,len($member.name),1) <> Chr(36)
          $temparray[$i] = $member.name
 
          select
            case $adsiflag = 8
              $temparray[$i] = $member.adspath
 
            case $adsiflag = 16
              $temparray[$i] = $member
 
          endselect
 
          $i = $i + 1
 
        endif
 
      case $filterflag
        ;bit bucket 
 
    endselect
 
    if $i = ubound($temparray)
      redim preserve $temparray[Ubound($temparray)+$chunk]
 
    endif
 
  next
 
  if $i <> 0
    redim preserve $temparray[$i-1]
    $groupmembers=$temparray
 
  endif
 
endfunction


LonkeroAdministrator
(KiX Master Guru)
2009-03-30 08:23 PM
Re: User Account Locked Notification

well, this won't work:
 Code:
$LStat = $objUser.IsAccountLocked

If $LStat = TRUE


as it actually says something like this on locked accounts:
 Code:
if -1 = 0


JeffS
(Fresh Scripter)
2009-03-30 08:29 PM
Re: User Account Locked Notification

I thought AD reports a Locked Out status as a Boolean. So either TRUE or FALSE?

Or am I missing the boat here. Actually I bet I am missing the boat! :-)


Glenn BarnasAdministrator
(KiX Supporter)
2009-03-30 08:42 PM
Re: User Account Locked Notification

Notice the original example
 Code:
  If $LStat  
It doesn't compare it to anything, just tests to see if it's true (non-zero). The
 Code:
If $LStat = TRUE
really should not have the "= TRUE" part, but it does work because "TRUE" evaluates to non-zero. Not a good way to implement, I agree, but it does work.

Glenn


JeffS
(Fresh Scripter)
2009-03-30 09:04 PM
Re: User Account Locked Notification

If I remove the "=TRUE" part, the list come back blank. Even if there are locked accounts, so I figured I needed some type of qualifier.

JeffS
(Fresh Scripter)
2009-03-30 09:12 PM
Re: User Account Locked Notification

Unless the issue is with the domain I am in I can't figure this out.

If I run the above script, it says that every account in the Domain is NOTLOCKED. However, if I lock out one of the accounts and replicate that information to all of the DC's in the domain, and I verify by using LockOutStatus.exe then rerun the report the username does not show up in the list and no accounts are shown as being locked out.

I am confused of why it is doing it, any suggestions?