Home Up Feedback

Integer8 Attributes

Integer8 Discussion

Many attributes in Active Directory have a data type (syntax) called Integer8. These 64-bit numbers (8 bytes) usually represent time in 100-nanosecond intervals. If the Integer8 attribute is a date, the value represents the number of 100-nanosecond intervals since 12:00 AM January 1, 1601.

ADSI automatically employs the IADsLargeInteger interface to deal with these 64-bit numbers. This interface has two property methods, HighPart and LowPart, which break the number up into two 32-bit numbers. The LowPart property method returns values between -2^31 and 2^31 - 1. The standard method of handling these attributes is demonstrated by this VBScript program to retrieve the domain lockoutDuration value in minutes.

Set objDomain = GetObject("LDAP://dc=MyDomain,dc=com")

' Retrieve lockoutDuration with IADsLargeInteger interface.

Set objDuration = objDomain.lockoutDuration

' Calculate number of 100-nanosecond intervals.

lngDuration = objDuration.HighPart * (2^32) + objDuration.Lowpart

'  Convert to minutes.

lngDuration = -lngDuration / (60 * 10000000)

Wscript.Echo "Domain policy lockout duration in minutes: " & lngDuration

However, whenever the LowPart method returns a negative value, the calculation above is wrong by 7 minutes, 9.5 seconds. The work-around is to increase the value returned by the HighPart method by one whenever the value returned by the LowPart method is negative. The revised code below gives correct results in all cases.

Set objDomain = GetObject("LDAP://dc=MyDomain,dc=com")

' Retrieve lockoutDuration with IADsLargeInteger interface.

Set objDuration = objDomain.lockoutDuration

lngHigh = objDuration.HighPart

lngLow = objDuration.LowPart

' Adjust for error in IADsLargeInteger interface.

If lngLow < 0 then

  lngHigh = lngHigh + 1

End If

' Calculate number of 100-nanosecond intervals.

lngDuration = lngHigh * (2^32) + lngLow

'  Convert to minutes.

lngDuration = -lngDuration / (60 * 10000000)

Wscript.Echo "Domain policy lockout duration in minutes: " & lngDuration

The error introduced if this inaccuracy is not accounted for is not large. The error is always 2^32 100-nanosecond intervals, which is 7 minutes, 9.5 seconds. All the programs on this site that deal with Integer8 attributes have been revised as shown on this page to give accurate results.

The link on the left discusses the details of this problem and unsigned arithmetic. The revised function linked below can be used to convert Integer8 attributes to dates:

Integer8Date.txt   <<-- Click here to view or download the program

An alternative method to convert Integer8 values into dates uses the Windows time service tool w32tm.exe. This is included with Windows XP and Windows Server 2003 default installations. This tool can be used to convert 64-bit values to dates in the local time zone. The program must still use the IADsLargeInteger property methods to convert the Integer8 value to a 64-bit number. We must also account for the inaccuracy described above when the LowPart method returns a negative value. However, w32tm.exe takes the local time zone bias into account and converts a 64-bit value into a date and time in the local time zone. The program linked below also uses the Exec method of the wshShell object, so it requires WSH 5.6 as well as w32tm.exe. The example program demonstrating a function using w32tm.exe is linked here:

Integer8Date2.txt   <<-- Click here to view or download the program

If you use ADO to retrieve Integer8 attribute values, the following syntax will not invoke the IADsLargeInteger interface and will raise an error:

Do Until adoRecordset.EOF

    ' This does not invoke the IADsLargeInteger interface.

    Set objDate = adoRecordset.Fields("pwdLastSet")

    ' This statement raises an error.

    lngHigh = objDate.HighPart

    ' Likewise, the Intger8Date function, documented above,

    ' raises an error.

    dtmDate = Integer8Date(objDate, lngTZBias)

    adoRecordset.MoveNext
Loop

You must either specify the Value property of the Field object and use the Set keyword:

Do Until adoRecordset.EOF

    ' Specify the Value property of the Field object.

    Set objDate = adoRecordset.Fields("pwdLastSet").Value

    ' Invoke methods of the IADsLargeInteger interface directly.

    lngHigh = objDate.HighPart

    ' Or use the Integer8Date function documented in the link above.

    dtmDate = Integer8Date(objDate, lngTZBias)

    adoRecordset.MoveNext
Loop

Or, you must assign the value to a variant, and then use the Set keyword to invoke the IADsLargeInteger interface:

Do Until adoRecordset.EOF

    ' Assign the value to a variant.

    lngDate = adoRecordset.Fields("pwdLastSet")

    ' Use the Set keyword to invoke the IADsLargeInteger interface.

    Set objDate = lngDate

    ' Invoke methods of the IADsLargeInteger interface directly.

    lngHigh = objDate.HighPart

    ' Or use the Integer8Date function documented in the link above.

    dtmDate = Integer8Date(objDate, lngTZBias)

    adoRecordset.MoveNext
Loop

 
Send mail to HilltopLab@RLMueller.Net with questions or comments about this web site.
Copyright © 2002-2007 Richard L. Mueller
Last modified: May 02, 2008