Building LDAP filters for date based attributes

Active Directory contains a number of attributes which hold date information. This article shows how to generate LDAP Filters for these attributes in both VbScript and PowerShell.

Date attributes

This LDAP Filter format can be used for the following attributes:

  • createTimeStamp
  • dsCorePropagationData
  • expirationTime
  • modifyTimeStamp
  • whenChanged
  • whenCreated

VbScript

' The date the filter is supposed to find
dtmDate = Now() - 1
 
arrDateParts = Array("yyyy", "m", "d", "h", "n", "s")
 
For Each strInterval in arrDateParts
    intDatePart = DatePart(strInterval, dtmDate)
    If intDatePart < 10 Then
        strDateTime = strDateTime & "0" & intDatePart
    Else
        strDateTime = strDateTime & intDatePart
    End If
Next
strDateTime = strDateTime & ".0Z"

' WhenCreated is after strDateTime. i.e. objects created since strDateTime.
WScript.Echo "(whenCreated>=" & strDateTime & ")"

This will produce a filter like "(whenCreated>=20090826110816.0Z)". Accuracy is based on the source date, using Date() instead of Now() would result in accuracy to a day (e.g. "(whenCreated>=20090826000000.0Z)").

PowerShell

# Convert yesterday to a Universal date-time string
$DateString = (Get-Date).AddDays(-1).ToString("u") -replace "-|:|\s"
$DateString = $DateString -replace "Z", ".0Z"
 
Write-Host "(whenCreated>=$DateString)"

As with the VbScript version this returns a string accurate to seconds. Accuracy can be modified by using (Get-Date).Date.AddDays(-1).

Interger8 attributes

An Interger8 date is represented by the number of 100-nanosecond intervals since the Microsoft epoch (01/01/1601 00:00:00). This format applies to the following attributes:

  • accountExpires
  • badPasswordTime
  • lastLogon
  • lastLogonTimeStamp
  • lockoutTime
  • pwdLastSet

Note that lastLogoff also uses this format but the value for the attribute is not maintained by Active Directory.

VbScript

' The number of days to remove from the current date
Const DAYS_TO_REMOVE = 1

dblInt8 = CDbl(DateDiff("s", CDate("01/01/1601 00:00:00"), Now - DAYS_TO_REMOVE))
' Earlier than the current date. i.e. Passwords set before the generated date
WScript.Echo "(&(pwdLastSet<=" & CStr(dblInt8) & "0000000)(!pwdLastSet=0))"

This produces a filter like "(&(pwdLastSet<=128957595350000000)(!pwdLastSet=0))". As with the previous filter this is accurate to seconds, that can be modified by changing the source date in the same way as before.

PowerShell

$DaysToRemove = 1
$Int8Date = [Math]::Round(
  New-TimeSpan (Get-Date "01/01/1601 00:00:00") (((Get-Date).AddDays(-$DaysToRemove)).TotalSeconds, 0)

$Int8Date = "$($Int8Date.ToString())0000000"

$LdapFilter = "(&(pwdLastSet<=$Int8Date)(!pwdLastSet=0))"

accountExpires

Certain attributes, such as accountExpires, have default values that can make filtering using a date difficult.

The following LDAP filter can be used to return all accounts that are set to expire.

"(accountExpires<=9223372032559810000)(!accountExpires=0))"

Where 9223372032559810000 is the default attribute value in most cases, and 0 is the default in the rest.

accountExpires exhibits inconsistent behaviour depending on how it is accessed. If using iADSUser.AccountExpirationDate an account that does not expire is denoted by the date “01/01/1970 00:00:00”. This epoch date differs from the epoch used with the underlying attribute, “01/01/1601 00:00:00”.

Building LDAP filters for date based attributes
Share this