tachyon has asked for the wisdom of the Perl Monks concerning the following question:

Dear fellow monks,

I have been using perl to add some rationality into using Active Directory which is working pretty well with the help of Win32::Perm, ActiveDirectory.pm and ldifde(). The neat thing about ldifde() is that it writes text files that you can edit with perl and then process back through it modifying Active Directory in bulk. Anyway, in the output from the ldifde utility you get records that look like this (edited for brevity, linefeeds for clarity):

dn: CN=Telma Da Silva,OU=Admin Staff,OU=Ursuline,DC=admin,DC=merton,DC +=sch,DC=uk badPasswordTime: 126697423010137600 cn: Telma Da Silva countryCode: 0 displayName: Telma Da Silva givenName: Telma homeDirectory: \\Adminserver1\Users\td23 homeDrive: H: lastLogon: 126706756220988432 pwdLastSet: 126635260714951232 whenChanged: 20020627124211.0Z whenCreated: 20020417075229.0Z

whenChanged and whenCreated use ISO 8601 YYYYMMDDHHMMSS.0Z notation as suggested on the M$ site. My question is simple. The badPasswordTime, lastLogon and pwdLastSet seem to share a common time format but what is it? Equally important what Perl widget will change it to a more standard format? Last logon for this user would have been within the last week. It is currently around (126711457518591600) according to M$.

cheers

tachyon

s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Replies are listed 'Best First'.
Re: Active Directory ldifde() time format conversion question
by jmcnamara (Monsignor) on Jul 15, 2002 at 08:29 UTC

    This looks like a Windows VT_FILETIME data type which is a 64 bit unsigned integer representing the number of elapsed 100 nanoseconds since 1 January 1601. A quick check with bc seems to put it in the right ballpark (omitting leap-days):
    $ bc 2002-1601 401 401*365*24*60*60*10^7 126459360000000000

    There are functions to do this conversion buried in the internals of OLE::Storage and OLE::Storage_Lite and perhaps in some other Win32 modules as well. But you could roll your own conversion with Date::Calc:

    #!/usr/bin/perl -wl use strict; use Date::Calc 'Add_Delta_DHMS'; my $vt_filetime = '126697423010137600'; # Disregard the 100 nanosecond units (rounding might be better) $vt_filetime = substr($vt_filetime, 0, 11); my $days = int( $vt_filetime / (24*60*60) ); my $hours = int( ($vt_filetime % (24*60*60)) / (60*60) ); my $mins = int( ($vt_filetime % (60*60)) / 60 ); my $secs = $vt_filetime % 60 ; my @date = Add_Delta_DHMS(1601, 1, 1, 0, 0, 0, $days, $hours, $min +s, $secs); # Format @date as you wish print "@date"; __END__ Prints: 2002 6 28 12 51 41

    --
    John.

Re: Active Directory ldifde() time format conversion question
by strat (Canon) on Jul 15, 2002 at 11:26 UTC
    With ldifde, I've got big problems with binary values; e.g. when I exported some trees containing binary stuff (e.g. german umlauts, certificates) to a file and tried to reimport the file, it often failed because ldifde didn't understand the format it has been written.

    For this and several other reasons (e.g. a directory normally doesn't like to get it's data completely deleted and reimported and takes revenge with huge memory usage and big "databases"), I changed to in- and exporting and also synchronizing stuff with Net::LDAP (also called Perl::LDAP on CPAN).

    Best regards,
    perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"

Re: Active Directory ldifde() time format conversion question
by mrbbking (Hermit) on Jul 15, 2002 at 00:58 UTC