This discussion has been locked. The information referenced herein may be inaccurate due to age, software updates, or external references.
You can no longer post new replies to this discussion. If you have a similar question you can start a new discussion in this forum.

Problem with APM template for locked out user account

I'm having an issue with the Shared APM template for AD account lock outs.  I'm specifically speaking about the one that Peter.Cooper posted in December of 2009.  It seems to work just fine, but it would be really useful if it would tell you the user account that is locked out.  Right now the only output I really get out of it is the number of accounts that are locked out.  Is what I'm asking for possible with APM?  I've searched quite a few other threads and haven't been able to find an answer yet.  If anyone has experience with this, I would appreciate any assistance.

  • Hi dburgett--

    I'll ping Peter directly and see if he's available to help.

    Thanks!

    M

  • Hey there.

    What's cool about this implementation is that we're using a script to transmit a number and some text... and all the source code is available for modification.

    It is possible to modify the script to do an additional step and retrieve the name of accounts, and then append them to the 'message' we're sending back. Right now the script sends back how many users are locked out.

    Do you have any IT staff that can enhance this script? If not, I can take another peek.

    Peter.

  • One of my Systems Engineers is going to take a look at the script and see if he can figure it out.  If you have a chance, and you know how to get it returning the results I would like, I would greatly appreciate it.  :)

  • We got a script working to show us the names of the user accounts that are currently locked out.  I have pasted it below.  A lot of it is using the script from the template that was shared by Peter.

    Option Explicit
    const INVALID_PARAMS = 1, SUCCESS = 0, FAIL = 1
    Const ADS_UF_ACCOUNTDISABLE = 2

    Dim objRootDSE, strDNSDomain, objDomain, adoCommand, adoConnection
    Dim strBase, strFilter, strAttributes, strQuery, adoRecordset, strMessage
    Dim strDN, strUser, strPassword, objNS, strServer, strPrefix, lst_args, arg_count
    Dim objShell, lngBiasKey, lngBias, lngHigh, lngLow, objDuration, lngDuration, lngSeconds, dtmLockout, str64Bit
    Dim UserCount, FoundRet, DoAuth, intUAC

    Const ADS_SECURE_AUTHENTICATION = &H1
    Const ADS_SERVER_BIND = &H200

    intUAC = 0
    UserCount = 0
    FoundRet = SUCCESS
    strPrefix = ""

    Set lst_args = WScript.Arguments

    if lst_args.Count > 0 Then
    else
       WScript.Echo "Message: Usage: wscript.exe UsersLockedOut.vbs -computer ComputerName " & vbCRLF _
       & "-computer The computer name "  &vbCRLF _
       & "-user UserName of the account to use" & vbCRLF _
       & "-password Password to connect with" & vbCRLF _
       & "-prefix Text to prefix the query filter to a particular OU or CN. ex.: cn=Engr,ou=East" & vbCRLF _
       & "-downiffound If present, the monitor will be down if found" & vbCRLF
       WScript.Echo "Statistic: 0"
       WScript.Quit( FAIL )
    End if

    for arg_count = 0 to lst_args.Length - 1
                    if lst_args(arg_count) = "-computer" Then
                       strServer = lst_args(arg_count + 1)
                       arg_count = arg_count + 1
                    elseif lst_args(arg_count) = "-user" Then
                       strUser = lst_args(arg_count + 1)
                       if strUser <> "" Then DoAuth = 1
                       arg_count = arg_count + 1
      elseif lst_args(arg_count) = "-password" Then
                       strPassword = lst_args(arg_count + 1)
                       if strPassword <> "" Then DoAuth = 1
           arg_count = arg_count + 1
      elseif lst_args(arg_count) = "-prefix" Then
           strPrefix = lst_args(arg_count + 1) & ","
           arg_count = arg_count + 1
      elseif lst_args(arg_count) = "-downiffound" Then
                       FoundRet = FAIL
      End if
    Next

    On Error Resume Next

    '' Obtain local Time Zone bias from local machine registry.
    Set objShell = CreateObject("Wscript.Shell")
    lngBiasKey = objShell.RegRead("HKLM\System\CurrentControlSet\Control\" _
    & "TimeZoneInformation\ActiveTimeBias")
    if (UCase(TypeName(lngBiasKey)) = "LONG") Then
    lngBias = lngBiasKey
    elseif (UCase(TypeName(lngBiasKey)) = "VARIANT()") Then
    lngBias = 0
    for k = 0 To UBound(lngBiasKey)
    lngBias = lngBias + (lngBiasKey(k) * 256^k)
    Next
    End if
    Set objShell = Nothing

    ' Determine DNS domain name. Use server binding and alternate
    ' credentials. The value of strDNSDomain can also be hard coded.
    Set objNS = GetObject("LDAP:")

    Err.Clear
    if (DoAuth > 0) Then
    Set objRootDSE = objNS.OpenDSObject("LDAP://" & strServer & "/RootDSE", _
         strUser, strPassword, _
         ADS_SERVER_BIND Or ADS_SECURE_AUTHENTICATION)
    else
    Set objRootDSE = GetObject("LDAP://" & strServer & "/RootDSE")
    End if

    if Err.Number <> 0 Then HandleError

    Err.Clear
    strDNSDomain = objRootDSE.Get("defaultNamingContext")

    if Err.Number <> 0 Then HandleError

    Err.Clear
    if (DoAuth > 0) Then
    set objDomain = objNS.OpenDSObject("LDAP://" & strServer & "/" & strDNSDomain, _
         strUser, strPassword, _
         ADS_SERVER_BIND Or ADS_SECURE_AUTHENTICATION)
    else
    set objDomain = GetObject("LDAP://" & strServer & "/" & strDNSDomain )
    End if

    ''Retrieve domain lockoutDuration policy in minutes.

    Set objDuration = objDomain.lockoutDuration
    lngHigh = objDuration.HighPart
    lngLow = objDuration.LowPart
    if (lngLow < 0) Then
    lngHigh = lngHigh + 1
    End if
    lngDuration = lngHigh * (2^32) + lngLow
    lngDuration = -lngDuration/(60 * 10000000)
    Set objDomain = Nothing

    ' Determine lockout time in the past that would just
    ' have expired. Accounts locked out since this time would
    ' still be locked out.
    dtmLockout = DateAdd("n", -lngDuration, Now())

    ' Convert to UTC.
    dtmLockout = DateAdd("n", lngBias, dtmLockout)

    ' Find number of seconds since 1/1/1601.
    lngSeconds = DateDiff("s", #1/1/1601#, dtmLockout)

    ' Convert to 100-nanosecond intervals. This is the
    ' equivalent Integer8 value.
    str64Bit = CStr(lngSeconds) & "0000000"

    Err.Clear

    ' Use ADO to search Active Directory.
    ' Use alternate credentials.
    Set adoCommand = CreateObject("ADODB.Command")
    Set adoConnection = CreateObject("ADODB.Connection")
    adoConnection.Provider = "ADsDSOObject"
    if (DoAuth > 0) Then
    adoConnection.Properties("User ID") = strUser
    adoConnection.Properties("Password") = strPassword
    adoConnection.Properties("Encrypt Password") = True
    adoConnection.Properties("ADSI Flag") = ADS_SERVER_BIND _
         Or ADS_SECURE_AUTHENTICATION
    End if
    adoConnection.Open "Active Directory Provider"
    if Err.Number <> 0 Then HandleError

    Set adoCommand.ActiveConnection = adoConnection

    ' Search entire domain. Use server binding.
    strBase = "<LDAP://" & strServer & "/" & strPrefix & strDNSDomain & ">"

    ' Search for all users.
    strFilter = "(&(objectCategory=person)(objectClass=user)(lockoutTime>=" & str64Bit & "))"

    ' Comma delimited list of attribute values to retrieve.
    strAttributes = "distinguishedName, displayName, userAccountControl"

    ' Construct the LDAP query.
    strQuery = strBase & ";" & strFilter & ";" _
         & strAttributes & ";subtree"

    ' Run the query.
    adoCommand.CommandText = strQuery
    adoCommand.Properties("Page Size") = 1000
    adoCommand.Properties("Timeout") = 30
    adoCommand.Properties("Cache Results") = False
    strMessage = "The following user(s) are Locked Out: "
    Set adoRecordset = adoCommand.Execute

    if Err.Number <> 0 Then
        HandleError
    End if

    On Error Goto 0

    ' Enumerate the resulting recordset.
    do until adoRecordset.EOF
         ' Retrieve values.
         intUAC=adoRecordset.Fields("userAccountControl")
         If intUAC AND ADS_UF_ACCOUNTDISABLE Then
                    adoRecordset.MoveNext

         else
        
                    strMessage = strMessage  & adoRecordset.Fields("displayName")
                    UserCount = UserCount + 1
                    adoRecordset.MoveNext
                                    If adoRecordset.EOF = False Then
                                    strMessage = strMessage & "; "
                    End If
                   
         End If
        
         intUAC = 0

    Loop

    ' Clean up.
    adoRecordset.Close
    adoConnection.Close

    if (UserCount > 0) Then
     Wscript.Echo "Statistic: " & UserCount
     Wscript.Echo "Message: " & strMessage
     Wscript.quit(FoundRet)
    else
     Wscript.Echo "Statistic: 0"
     Wscript.Echo "Message: No Users are locked out"
     Wscript.quit(SUCCESS)
    End if

    Sub HandleError
        WScript.Echo Replace( Replace( "Message: " &  Err.Source & ", " & Err.Description & " (Hex): " & Hex(Err.Number), vbCrLf, ""), vbCr, "")
        Wscript.quit(FAIL)
    End Sub

  • Love the script works great, but would like to be able to define a few OU's to search in, but I am no VB programmer. Is there anything that could help with that.  I want the query to look at 3 or 4 OU's I set in a variables to search in.

  • FormerMember
    0 FormerMember

    Does anyone have an alert built for this script monitor?

  • Love the script, but wouldn't it be easier to just convert it to a PowerShell script?

    Import-Module ActiveDirectory
    $LockedAccounts = Search-ADAccount -LockedOut
    if ( $LockedAccounts )
    {
        Write-Host "Message: The following accounts are locked out: $( ( $LockedAccounts | Sort-Object -Property Name ).Name -join "; " )
        Write-Host "Statistic: $( $LockedAccounts.Count )"
    }
    else
    {
        Write-Host "Message: No accounts are locked out"
        Write-Host "Statistic: 0"
    }