joeware - never stop exploring... :)

Information about joeware mixed with wild and crazy opinions...

From the mailbag: Searching for objects within specific date ranges – Generalized Time Attributes

by @ 11:42 pm on 4/26/2011. Filed under tech

I received the following email last month and figured it was worth writing up because it involves an LDAP query and Generalized Time which I don’t believe I have previously written about. Also part of this email made me chuckle, I won’t indicate which part. Winking smile

From: xxxxx
Sent: Thursday, March 03, 2011 7:30 PM
To: joe@joeware.net
Subject: Help Please

Hi Joe,
Can you help me? I am looking to use ADFind.exe to locate all users in the GC that were created on a specific date range based no the whenCreated attribute and export the name, userprincipalname, samaccountname and whencreated attributes to a CSV.

Is this possible with your utility? If so, can you show me the syntax?

I have written a .NET application to gather this info but it is just too slow.

Thanks in advance,
xxxxx

This query is pretty basic for AdFind and I have spoken at length about how to specify bases and returning attributes etc so the piece I will discuss here will be the LDAP filter and specifically, the pieces specific to the time.

Generalized Time is one of the ways that time is represented in Active Directory. Certain attributes like whenCreated and whenChanged use this format which looks like:

>whenCreated: 20110323183100.0Z

If you look closely you can see that the format is

“YYYYMMDDHHMMSS.0Z”

  • YYYY – Four digit year
  • MM – two digit month
  • DD – two digit day
  • HH – two digit military time format hour
  • MM – two digit minute
  • SS – two digit second
  • .0Z which stands for ZULU time, i.e. UTC.

When creating queries with Generalized Time you can use

  • an EXISTS query (i.e. attribute=* or the NOT of that)
  • an EQUALS query (i.e. attribute=somevalue)
  • a RANGE query (i.e attribute>=somevalue or attribute<=somevalue or some combination)

EXISTS and EQUALS queries are pretty rare in my opinion for Generalized Time attributes. When you perform an EQUALS query, the value has to be exactly correct. If you are looking for something, you usually won’t have a value down to the second unless you are trying to find everything that was created at the same time something else was created and use that object’s whenCreated value. RANGE based queries, on the other hand, are common. When performing those queries you can “zero out’ pieces of the time format. For example, you don’t have to specify hours, minutes or seconds so the actual value could look something like 20110401000000.0Z to indicate the very beginning of April 1, 2011.

So with the understanding that you must always use >= or <= versus > and < and the Generalized Time Format listed above combined with the possible values it is pretty easy to build your LDAP queries. To specify an object creation range of say the month of April 2011, the query would be

(&(whencreated>=20110401000000.0Z)(whencreated<=20110501000000.0Z))

If you need to know what objects were created within a certain hour or range of hours, this is a little more tricky UNLESS you know the actual UTC values to specify. Generalized Time allows you to specify something other than ZULU / UTC time, specifically, you can specify a time with offset, that looks like “YYYYMMDDHHMMSS.0[+/-]HHMM”. A simple example to return the objects created between 1PM and 5PM UTC on April 1 would be

(&(whencreated>=20110401130000.0Z)(whencreated<=20110401170000.0Z))

Of course unless you want every single object class that could have been created in the search scope for the given time range, you will want to specify an objectCategory or some other indexed attribute.

Before I close this post out, let me add one little note… The note is about whenChanged. While whenCreated is a replicated attribute and will be the same for a given object across all DCs, whenChanged is NOT replicated, repeat it is NOT replicated. This means that while you can successfully use whenCreated to search for objects created in a specific range, using whenChanged may not be as helpful especially if you are querying different DCs at different times. Since whenChanged isn’t replicated, the value will be based on when the actual change got to that actual DC, not when it was mastered on some other DC.

Don’t believe me… The Active Directory schema says the same thing…

F:\Dev\cpp\AdFind>adfind -sc s:whenchanged

AdFind V01.45.00cpp Joe Richards (joe@joeware.net) March 2011

Using server: K8R2Dom-DC1.k8r2dom.loc:389
Directory: Windows Server 2008 R2
Base DN: CN=Schema,CN=Configuration,DC=k8r2dom,DC=loc

dn:CN=When-Changed,CN=Schema,CN=Configuration,DC=k8r2dom,DC=loc
>objectClass: top
>objectClass: attributeSchema
>cn: When-Changed
>distinguishedName: CN=When-Changed,CN=Schema,CN=Configuration,DC=k8r2dom,DC=loc
>instanceType: 4 [WRITABLE(4)]
>whenCreated: 20090211173717.0Z
>whenChanged: 20090211173717.0Z
>uSNCreated: 1197
>attributeID: 1.2.840.113556.1.2.3
>attributeSyntax: 2.5.5.11 [STRING (UTC/GENERALIZED-TIME)]
>isSingleValued: TRUE
>mAPIID: 12296
>uSNChanged: 1197
>showInAdvancedViewOnly: TRUE
>adminDisplayName: When-Changed
>adminDescription: When-Changed
>oMSyntax: 24 [STRING (GENERALIZED-TIME)]
>searchFlags: 0 []
>lDAPDisplayName: whenChanged
>name: When-Changed
>objectGUID: {1431D635-9F30-488F-A0BE-86FB07149487}
>schemaFlagsEx: 1 [FLAG_ATTR_IS_CRITICAL(1)]
>schemaIDGUID: {BF967A77-0DE6-11D0-A285-00AA003049E2}
>systemOnly: TRUE
>systemFlags: 19 [NOT REPLICATED(1);PAS-ATTR(2);CAT-1(16)]
>isMemberOfPartialAttributeSet: TRUE
>objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=k8r2dom,DC=loc
>dSCorePropagationData: 16010101000000.0Z

1 Objects returned

   joe

Rating 3.50 out of 5

One Response to “From the mailbag: Searching for objects within specific date ranges – Generalized Time Attributes”

  1. Mike Kline says:

    Not only is this a mailbag question this is one of the most common questions I see on various forums. Nice work as usual joe!

    Thanks

    Mike

[joeware – never stop exploring… :) is proudly powered by WordPress.]