The Active Directory Integer8 data type is used to represent dates. Integer8
values are 64-bit (8-byte) integers that represent dates as the number of
100-nanosecond intervals since 12:00 AM January 1, 1601. In PowerShell,
these 100-nanosecond intervals are called ticks. PowerShell represents dates
as the number of ticks since 12:00 AM January 1, 0001. Remember, there was
no year 0000. The previous day was December 31, 0001 BC. Leap seconds are
not accounted for. In addition, the switch from the Julian to Gregorian
calendars in 1582, when October 4, 1582, was followed by October 15, is
ignored.
The following table
shows the number of ticks equivalent to several dates.
Date (UTC) | PowerShell Ticks | AD Ticks |
January 1, 0001, 00:00:00 | 0 | N/A |
January 1, 1601, 00:00:00 | 504,911,232,000,000,000 | 0 |
March 21, 2011, 00:00:00 | 634,362,624,000,000,000 | 129,451,392,000,000,000 |
December 31, 9999, 23:59:59.9999999 | 3,155,378,975,999,999,999 | 2,650,467,743,999,999,999 |
September 14, 30828, 02:48:05.478 | N/A | 9,223,372,036,854,775,807 |
The difference between the number of PowerShell (or .NET Framework) ticks
and the number of Active Directory Integer8 ticks corresponding to any particular date is the
number of ticks in 1600 years. This is 1600 * 365.2425 * 24 * 60 * 60 *
10000000 = 504,911,232,000,000,000 ticks.
Why
make note if this? Well, first, we sometimes need to convert between
PowerShell and Active Directory dates. This is easily done by adding or
subtracting the equivalent of 1600 years. However, it is also possible for
the Active Directory accountExpires attribute to have the maximum value
possible for a 64-bit number, which is 2^63 -1, or
9,223,372,036,854,775,807. If an Active Directory account has never had an
expiration date, this is the value assigned to the accountExpires attribute.
It really means "never". However, the .NET Framework defines a maximum value
for the ticks in a DateTime value, which is the number of ticks in the date
December 31, 9999, 23:59:59.9999999. If a PowerShell script attempts to
convert the integer 2^63 -1 into a date, an error is raised. The script must
test for this condition and assign a value equivalent to "never" before
attempting to convert into a DateTime value. The following
PowerShell script demonstrates how to retrieve the account expiration date
for a specified Active Directory user. This can be used in PowerShell V1 or
V2:
$User = [ADSI]"LDAP://CN=Jim Smith,ou=West,dc=MyDomain,dc=com"
$AcctExp = $User.accountExpires.Value
$lngValue = $User.ConvertLargeIntegerToInt64($AcctExp)
# A value of 0 or 2^63-1 means never.
If ($lngValue -gt [DateTime]::MaxValue.Ticks)
{
$lngValue = 0
}
# Convert 64-bit integer into DateTime.
$Date = [DateTime]$lngValue
If ($Date -eq 0)
{
$AcctExpires = "<Never>"
}
Else
{
# Convert Active Directory ticks to PowerShell ticks.
# Also convert from UTC to local time.
$AcctExpires = $Date.AddYears(1600).ToLocalTime()
}
$AcctExpires
The expression [DateTime]::MaxValue in the code above is the maximum date in the .NET Framework, December 31, 9999, 23:59:59.9999999. The expression [DateTime]::MaxValue.Ticks is the equivalent in PowerShell ticks, or 3,155,378,975,999,999,999. A similar script using the Active Directory module Get-ADUser would be as follows. This requires PowerShell V2:
$User = Get-ADUser -Identity jsmith -Properties accountExpires
$lngValue = $User.accountExpires
If (($lngValue -eq 0) -or ($lngValue -gt [DateTime]::MaxValue.Ticks))
{
$AcctExpires = "<Never>"
}
Else
{
$Date = [DateTime]$lngValue
$AcctExpires = $Date.AddYears(1600).ToLocalTime()
}
$AcctExpires