none
How to query user accounts with criteria based on "ms-DS-User-Account-Control-Computed" attribute in AD RRS feed

  • Question

  • Trying to create an LDAP query that finds all user accounts that have an expired password, but I'm unable to query the accounts based on search criteria for "ms-DS-User-Account-Control-Computed" (equal to 8388608 per https://msdn.microsoft.com/en-us/library/ms677840.aspx). Does anyone know how to create that LDAP query?
    Sunday, May 3, 2015 10:30 PM

Answers

  • Ah, the msDS-User-Account-Control-Computed attribute is operational, also called constructed. I failed to check that. It means the value is not actually saved in Active Directory, but instead is calculated by the domain controller on request. That makes sense in this case when you think about. After all, the name implies "computed". You can retrieve the values of operational attributes in a query (if they are single valued), but they cannot be used in a filter. Other examples of single valued operational attributes that cannot be used in filters are canonicalName, createTimestamp, and modifyTimestamp.

    There is no fix for this, since the value is not really saved in AD. The fix in PowerShell would be to retrieve all user objects and the value of their msDS-User-Account-Control-Computed attributes, then use a Where clause to only consider those that meet your condition. If you cannot use Search-ADAccount, and you cannot process the resultset after it is retrieved from the DC, then you are stuck.

    Edit: Oh, and jrv is correct, your filter has too many clauses. Only three are needed.


    Richard Mueller - MVP Directory Services


    Monday, May 4, 2015 3:34 PM
    Moderator

All replies

  • Try:

    Search-AdAccount -PasswordExpired -UsersOnly


    \_(ツ)_/


    • Edited by jrv Sunday, May 3, 2015 10:58 PM
    Sunday, May 3, 2015 10:58 PM
  • The LDAP syntax filter for all users where the Password_Expired bit of the attribute is set would be:

    (&(objectCategory=person)(objectClass=user)(msDS-User-Account-Control-Computed:1.2.840.113556.1.4.803:=8388608)
    This can be used with the dsquery * command line utility at the command line of a DC. Or this can be used with the -LDAPFilter parameter of Get-ADUser, but the you would not need the first two clauses of the filter (specifying objectCategory and objectClass) since that cmdlet only deals with user objects. Also note you must use the lDAPDisplayName of the attribute, which does not include a dash between "ms" and "DS".

    Richard Mueller - MVP Directory Services

    Sunday, May 3, 2015 11:18 PM
    Moderator
  • Didn't realize that the lDAPDisplayName was different. Thanks for pointing it out. I think it's working now, but i might not be getting any results back because no password is expired. Will play around with it to confirm. 

    Query used: "(&(objectCategory=person)(objectClass=user)(&(objectCategory=Person)(objectClass=User)(msDS-User-Account-Control-Computed:1.2.840.113556.1.4.1460:=8388608)))"



    Monday, May 4, 2015 12:44 AM
  • Thanks! Got to love PS....
    Monday, May 4, 2015 1:18 AM
  • The string 1.2.840.113556.1.4.803 specifies LDAP_MATCHING_RULE_BIT_AND. I see you substituted the attribute ID, but that will not work. This article explains all of the matching rules I know of:

    https://msdn.microsoft.com/en-us/library/aa746475(v=VS.85).aspx


    Richard Mueller - MVP Directory Services

    Monday, May 4, 2015 1:37 AM
    Moderator
  • To clarify, I'm running the query from an endpoint and not the server.

    When I run the query with the 803 value you referenced I get the below error in powershell. Also it doesn't seem to run in AD Users and Computers\Custom Search\Advanced (LDAP query) using only the filter string in the command below.

    Command: 

    Get-ADUser -LDAPFilter "(&(objectCategory=person)(objectClass=user)(&(objectCategory=Person)(objectClass=User)(msDS-User-Account-Control-Computed:1.2.840.113556.1.4.803:=8388608)))" 

    Error: 

    Get-ADUser : A Filter was passed that uses constructed attributes
    At line:1 char:1
    + Get-ADUser -LDAPFilter "(&(objectCategory=person)(objectClass=user)(&(objectCate ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [Get-ADUser], ADException
        + FullyQualifiedErrorId : A Filter was passed that uses constructed attributes,Microsoft.ActiveDirectory.Management.Commands.GetADUser

    Any help is appreciated.


    • Edited by F.Dagher Monday, May 4, 2015 2:35 PM clarification
    Monday, May 4, 2015 2:19 PM
  • Look closely at your filter.  Yo made some typos in using it.


    \_(ツ)_/

    Monday, May 4, 2015 2:40 PM
  • Ah, the msDS-User-Account-Control-Computed attribute is operational, also called constructed. I failed to check that. It means the value is not actually saved in Active Directory, but instead is calculated by the domain controller on request. That makes sense in this case when you think about. After all, the name implies "computed". You can retrieve the values of operational attributes in a query (if they are single valued), but they cannot be used in a filter. Other examples of single valued operational attributes that cannot be used in filters are canonicalName, createTimestamp, and modifyTimestamp.

    There is no fix for this, since the value is not really saved in AD. The fix in PowerShell would be to retrieve all user objects and the value of their msDS-User-Account-Control-Computed attributes, then use a Where clause to only consider those that meet your condition. If you cannot use Search-ADAccount, and you cannot process the resultset after it is retrieved from the DC, then you are stuck.

    Edit: Oh, and jrv is correct, your filter has too many clauses. Only three are needed.


    Richard Mueller - MVP Directory Services


    Monday, May 4, 2015 3:34 PM
    Moderator
  • OR - test expiration date.  Get lastsetdate and add pwdAge and test.


    \_(ツ)_/

    Monday, May 4, 2015 3:51 PM
  • jv gives me another idea, assuming PowerShell is not an option. You can filter on users where the pwdLastSet attribute is less than the LargeInteger value that corresponds to your domain maximum password age. For example, if passwords expire in 90 days, the LargeInteger value that corresponds to Feb. 4, 2015 is 130,674,996,000,000,000. The LDAP filter would be:

    (&(objectCategory=person)(objectClass=user(pwdLastSet<=130674996000000000))

    This would include disabled users, so you might need another clause. Also, you will need to calculate the LargeInteger value each time you make the query. And, this ignores PSO's.

    Richard Mueller - MVP Directory Services

    Monday, May 4, 2015 4:06 PM
    Moderator
  • There are many ways to calculate the LargeInteger value that corresponds to a date 90 days in the past. In PowerShell:

    $LargeInt = (Get-Date).AddDays(-90).ticks - 504911232000000000
    $LargeInt
    

    The exact value depends on your local time zone and when you run the code. The last 9 digits are not significant (unless milliseconds matter). The number 504,911,232,000,000,000 is the number of ticks (100-nanosecond intervals) between the PowerShell "zero" date of 12:00 AM January 1, 0001, and the Active Directory "zero" date of 12:00 AM January 1, 1601 (the ticks in 1600 years, ignoring calendar issues).

    Richard Mueller - MVP Directory Services

    Monday, May 4, 2015 4:26 PM
    Moderator
  • How about:

    $pwdLastSet +([timespan]'90:0:0:0').Ticks

    Here is how it works:

    New-Object System.datetime(([datetime]::Today).Ticks+([timespan]'90:0:0:0').Ticks)


    \_(ツ)_/

    Monday, May 4, 2015 5:31 PM