Fun stuff.  I have a department manager who wants to issue 100 Exchange
mailboxes, then revoke those that haven't logged in in 60 days, so they
can be deleted and the licenses re-used.  I believe this is what I'm
looking at running against every DC I have, then concatenating those
results.  Unless someone knows an easier way?

Oh, for Netware's NLIST utility:
NLIST USER WHERE "LAST LOGIN TIME" LT 12/14/01 (no logon since 12/14/01)
NLIST USER WHERE "LAST LOGIN TIME" NEXISTS  (no logon since forever)

-----Original Message-----
From: Krueger, Jason [mailto:[EMAIL PROTECTED]] 
Sent: Thursday, February 14, 2002 10:13 AM
To: '[EMAIL PROTECTED]'
Subject: RE: [ActiveDir] accountExpires field


> From: Al Lilianstrom [mailto:[EMAIL PROTECTED]]
> 
> Hi,
> 
> I'm managing AD accounts from a Unix system via LDAP. I'm
> trying to set
> the accountExpires field with the proper value.
> 
> The schema definition for the field is as follows;
> 
> Syntax - INTEGER8
> OID - 1.2.840.113556.1.4.159 
> 
> Digging deeper I find that this field is the number of seconds since 
> 00:00:00 on Jan 1, 1970 (Unix epoch time) expressed as a large 
> integer.

This is unfortunately horribly inaccurate.  I've reported it to
Microsoft a long while back, but I don't think they have yet cleaned up
all documenation references that state it as such.

Anything in AD that is a Date/Time attribute and uses the INTEGER8
syntax is using the same representation as the FILETIME format
(http://www.vbapi.com/ref/f/filetime.html).  The 64-bit integer is
actually the number of *100-nanosecond* intervals since Jan 1, 1601!!!
(no wonder it needs 64 bits!).

> For example - if I set an account (using AD Users&Computers) with a 
> account expiration date of Friday March 1, 2002 and then look at that 
> field using ldapsearch the field is
> 
> accountExpires: 126595224000000000

If you use the module I developed and have attached (DateTime.pm - put
it in your perl\site\lib\Win32 directory) you can convert to a human
readable GMT date using this oneliner: perl -MWin32::DateTime -e "print
scalar gmtime Win32::DateTime->new(big_int => shift)->utc_seconds"
126595224000000000 Sat Mar  2 06:00:00 2002

The module requires Win32::API, Math::BigInt, Date::Manip and a recent
version of Perl/ActivePerl.

Here's the minimal POD i've put in it so far
NAME
    Win32::DateTime - OO model for Win32 Date/Time conversion

SYNOPSIS
      use Win32::DateTime;

      # new() valid args:
      # utc_seconds - epoch seconds
      # big_int     - string decimal representation of 64-bit
LargeInteger
      # filetime    - either 8 byte packed struct, 2 integer element
array ref
      #               OR Win32::OLE LargeInteger object (from ADO)
      # systemtime  - 16 byte packed struct
      my $dt = Win32::DateTime->new(utc_seconds => time());
      print $dt->utc_seconds; # secs since epoch (midnight 1970 GMT)
      print $dt->filetime;    # filetime structure
      print $dt->big_int;     # big integer object
      print $dt->big_int_string; # useful in ADO queries
      print $dt->systemtime;  # much like what localtime() returns

DESCRIPTION
    Helps you convert between the many ugly date/time formats that one
has
    to deal with on windows and especially Active Directory.

  EXPORT

    None by default.

AUTHOR
     [EMAIL PROTECTED]

SEE ALSO
     Math::BigInt
     Win32::API
     Date::Manip

> 
> If you convert that number (in seconds) to a date you get
> December 31st,
> 1969 as it is larger than expected by any of the perl code I've used.
> 
> If you convert the date, Friday March 1, 2002 to seconds
> since the epoch
> you get 1014962400 seconds. If you plug that number in as a expiration
> date via a ldapmodify to an account the date AD U&C returns 
> is Thursday
> Feb 14, 2002. Setting to any date using epoch seconds seems to set to
> the current date.

Odd behavior, but probably some sort of builtin failsafe since it
interpreted the date as somewhere in the 1600's.

> So after all that - does anyone know exactly how to calculate
> the number
> for that field?

The basic formula for UTC seconds <=> FILETIME 100-nanoseconds
conversion is

utc = floor((filetime - 116,444,736,000,000,000) / 10,000,000)

116,444,736,000,000,000 = number of 100-nanosecond intervals between
epoch and Jan 1, 1601 10,000,000 = number of 100-nanosecond intervals in
a second

Simple formula but requires 64-bit integer math so it's not trivial on
32-bit platform.  That's why I needed to use Math::BigInt.  I also have
conversions <=> Win32 systemtime format.  If you want the gory details
you can examine the module code.

Cheers,
- Jason

PS: If the attachment gets filtered out, let me know and I'll try to
post it somewhere.



List info   : http://www.activedir.org/mail_list.htm
List FAQ    : http://www.activedir.org/list_faq.htm
List archive: http://www.mail-archive.com/activedir%40mail.activedir.org/

Reply via email to