Printout Header
RSS Feed

Microsoft Timestamp / Interval Attributes with Integer8 Syntax


On this web page we want to have a look at the numeric directory attributes which are used by Microsoft to express Date and Time values or Time Intervals. Examples for such attributes:

accountExpires
User objects
Computer objects
The date and time when the regarding account cannot be used any more.
badPasswordTime
User objects
Computer objects
The date and time when the regarding account has entered a bad password the last time.
lastLogoff
User objects
Computer objects
The date and time when the regarding account has logged off the last time (this isn't used in current AD versions).
lastLogon
User objects
Computer objects
The date and time when the regarding account has logged on to the domain (this is NOT replicated between domain controllers, so if you want to know the exact logon time for a certain user, you have to check all domain controllers)
lastLogonTimestamp
User objects
Computer objects
The date and time when the regarding account has logged on to the domain. The lastLogonTimestamp value is replicated between DCs, but only when the logon time is older than 2 weeks - this avoids replication traffic but shows us the accounts which hasn't been active for a long time.
lockoutDuration
Domain objects This is the time interval which determines how long an account is locked at the intruder lockout mechanism.
lockOutObservationWindow
Domain objects This is the time interval in which the user cannot enter a false password too often without being locked by the intruder lockout mechanism.
lockoutTime
User objects
Computer objects
For locked accounts, this is the date and time when the account was locked out.
maxPwdAge
Domain objects This is the time interval which determines the maximal password age for all users in the domain.
minPwdAge
Domain objects This is the time interval which determines the minimal password age for all users in the domain.
msDS-LastFailed
InteractiveLogonTime
User objects
The date and time when the regarding account failed to logon with an CTRL-ALT-DEL interactive logon. This doesn't return values on LDAP requests in AD versions older than 2008.
msDS-LastSuccessful
InteractiveLogonTime
User objects
The date and time when the regarding user did logon successfully with an CTRL-ALT-DEL interactive logon. This doesn't return values on LDAP requests in AD versions older than 2008.
msDS-UserPassword
ExpiryTimeComputed
User objects
Computer objects
The date and time when the password of the regarding user will be expired. This constructed attribute is described in the MSDN website, but doesn't return values on LDAP requests in AD versions older than 2008.
pwdLastSet
User objects The date and time when the regarding user changed his password the last time.

 

The basic LDAP attribute data type of these attributes is a Microsoft proprietary LDAP attribute syntax named Large Integer - it is often referred to as Integer8 because it's a signed numeric value which is 8 Bytes (64 bit) long. The possible range of a Microsoft Large Integer is this:

Minimum value:
-9223372036854775808 (-2^63)  or
hex 0x8000000000000000

Maximum value:

9223372036854775807 (2^63 - 1) or
hex 0x7FFFFFFFFFFFFFFF

 

 

So how is Microsoft using these really huge numbers as timestamp or interval values? As 'easy' as that:

In the ADSI API, Integer8 values are handled by accessing two 32 bit parts of the value: the HighPart and the LowPart. You should keep in mind that Active Directory stores all date and time values internally in the UTC format (Universal Coordinated Time) - this is (almost) the former Greenwich Meantime (GMT). So if your Systems are for example in Pacific Standard Time (PST, which is GMT-8), so you have to recalculate the Integer8 attribute values if you want to know the date and times in your local time.

Another important detail: You have to use the GetEx method to read a Large Integer/Integer8 attribute in an ADSI script. If you just try to read those attributes with Get, this runtime error will occur: 0x800a01b6 (-2146827850) METHOD_OR_PROPERTY_NOT_SUPPORTED.

So here is the script code to convert an Integer8 into a date and time, including the local time zone adjustment (we take the time abbreviation from UTC from the registry). Another sub function shows how to convert a date to Integer8:

'you have to use a distinguished name of an object from you own environment here! Set obj = GetObject("LDAP://cn=Administrator,cn=Users,dc=cerrotorre,dc=de") Set llValue = obj.Get("lastLogon") 'remember: use 'SET' to create an object! WScript.Echo LargeIntegerToDate(llValue) 'show the Integer8 value for the current date an time... WScript.Echo DateToLargeIntegerString(Now) Function LargeIntegerToDate(value) 'takes Microsoft LargeInteger value (Integer8) and returns according the date and time 'first determine the local time from the timezone bias in the registry Set sho = CreateObject("Wscript.Shell") timeShiftValue = sho.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias") If IsArray(timeShiftValue) Then timeShift = 0 For i = 0 To UBound(timeShiftValue) timeShift = timeShift + (timeShiftValue(i) * 256^i) Next Else timeShift = timeShiftValue End If 'get the large integer into two long values (high part and low part) i8High = value.HighPart i8Low = value.LowPart If (i8Low < 0) Then i8High = i8High + 1 End If 'calculate the date and time: 100-nanosecond-steps since 12:00 AM, 1/1/1601 If (i8High = 0) And (i8Low = 0) Then LargeIntegerToDate = #1/1/1601# Else LargeIntegerToDate = #1/1/1601# + (((i8High * 2^32) + i8Low)/600000000 - timeShift)/1440 End If End Function Function DateToLargeIntegerString(value) 'takes a date/time and returns the according Microsoft LargeInteger value (Integer8) 'first determine the local time from the timezone bias in the registry Set sho = CreateObject("Wscript.Shell") timeShiftValue = sho.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias") If IsArray(timeShiftValue) Then timeShift = 0 For i = 0 To UBound(timeShiftValue) timeShift = timeShift + (timeShiftValue(i) * 256^i) Next Else timeShift = timeShiftValue End If 'adjust the local time to UTC value = DateAdd("n", timeShift, value) 'how much seconds since 1601 are in the time? secs = DateDiff("s", #1/1/1601#, value) 'convert it to 100-nanosecond steps DateToLargeIntegerString = CStr(secs) & "0000000" End Function

Other tools to convert Microsoft Large Integer / Integer8 values to dates

There are several other tools to convert an Microsoft Large Integer (Integer8) value to a date.

LEX - The LDAP Explorer

LEX - The LDAP Explorer (a commercial powerful LDAP browser I developed) has special attribute editors for Large Integer values which have to be interpreted as Timestamps and Intervals:

Screenshot: Integer8 Attributes in the LEX LDAP Browser

LEX Editor for Microsoft Integer8 Timestamps:

Screenshots: Integer8 Attribute Editors for timestamps in LEX - The LDAP Explorer

LEX Editor for Microsoft Integer8 Intervals:

Screenshots: Integer8 Attribute Editors for intervals in LEX - The LDAP Explorer


W32TM


On the command line interface of each Windows machine since Windows Server 2003, you can use the W32TM.EXE command to convert an Integer8 to a date with this syntax:

 

W32TM /ntte <integer8-value>

Screenshot: Integer8 Attribute Conversion with W32TM


REPADMIN

 

On the command line interface of a domain controller, you cold use the REPADMIN.EXE command (on Windows 2000/2003 servers, you have to install the Ressource Kit to get REPADMIN.EXE). You can use this syntax:

REPADMIN /showtime <integer8-value>

But you have to omit the last 7 digits of the Large Integer, because REPADMIN wants to calculate with seconds and not with nanoseconds:

Screenshot: Integer8 Attribute Conversion with REPADMIN