Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Calculating lastLoginTimeStamp from Active Directory

by waxhead (Acolyte)
on Feb 16, 2007 at 10:05 UTC ( [id://600396]=perlmeditation: print w/replies, xml ) Need Help??

Fellow Monks,

I had a need today to find out when a person last logged into the network. It's a windows network, and the DC's are windows 2003 servers. So it has the one attribute needed to assist with this task, lastLogonTimestamp.

The issue with this value is though, it's a 64bit in of the number of 100 nanoseconds since 1/1/1601. Working out the date left me bit lost. Mostly because I was looking for the "right" way to do it, and I'm not saying that I have neccessarily hit on it the right way, but IF nothing else, this is at least a perl code sample for others to work on.

Of course this is a function where it's actually used, and the time stamp provided is an example only.

I hope I have it right, feel free to correct etc.

#!perl # it's run on windows that's why not a full path # Code Snippet to show how to get the date of the last login time # of an AD user on windows 2003 stored in the lastLogonTimestamp attri +bute. # # For more inforamtion about the value and windows use of Epoch, # basically put, the number of 100-nanosecond intervals that passed be +tween January 1, 1601 and the time the user last logged on # # Reference to the maths: http://www.microsoft.com/technet/scriptcente +r/topics/win2003/lastlogon.mspx # The document also covers the issue replication of this attribute, be + warned, the attribute # lastLogonTimestamp is replicated only once every 14 days. # # How to get the attribute out of AD is up to you. I was using Net::L +DAP at the time. # # Hopefully this will be found and help out anyone else stuck with thi +s problem. # use strict; # we need to handle the large int. It's a 64bit int use Math::BigInt; # Use Date::Calc to work out the days and date since 1/1/1600 use Date::Calc qw/Add_Delta_Days/; my $lastLoginTime = '127912653523035916'; my $loginTime = Math::BigInt->new( $lastLoginTime ); # Based on the document above and the words taken directly from: # there are 1,000,000,000 nanoseconds in a second; # therefore, there are 10,000,000 100-nanosecond intervals in a single + second (10,000,000 x 100 = 1,000,000,000). $loginTime = $loginTime / (60 * 10000000 ); # 60 seconds in a minute! # And because there are 1,440 minutes in every 24-hour day, this line +of code tells us how many days have elapsed: $loginTime = $loginTime / 1440; # and now, to get the date of the last login: my ($year,$month,$day) = Add_Delta_Days( 1601, 1, 1, $loginTime ); print "$year-$month-$day\n"; __END__

Replies are listed 'Best First'.
Re: Calculating lastLoginTimeStamp from Active Directory
by BrowserUk (Patriarch) on Feb 16, 2007 at 10:27 UTC

      Thanks, and yes, another way to do the same thing.

      Yet, nothing in the code examples really explains what's going on, or what the initial value (lastLogonTimeStamp) is derived from or why you calculate the number of days since etc.

      I can't claim that I'd know the numbers, but the first time I ever came across this timeStamp was in AD, and I'd think it's something more people will come across. Given the Lingua Franca of directories is LDAP, nearly anyone who has worked in this area would come across this, platform independent.

      The concept of slow really is an odd thing these days, with RAM capacities and CPU speeds what they are, what's the big deal, when it leads to, what I think, is a cleaner and clearer implementation.

      At least to start with. If you like the Perl fu way, then at least you know why you're typing in the numbers. :)

        The code I pointed to isn't a direct alternative to yours as it starts with the timestamps in their 8-byte binary form as you receive them from OS calls like GetFileTime(), GetThreadTimes() etc. You appear to be starting with them in ascii-ized form which means you don't need to unpack the binary representation.

        Still, re-calculating a constant each time you use it seemed a little unnecessary. Especially as once you've subtracted the constant difference betweeen 1/1/1601 and 1/1/1970, the numbers fall into a range that is easily handled without resorting to Math::BigInt.

        The concept of slow really is an odd thing these days, with RAM capacities and CPU speeds what they are, what's the big deal,

        That's exactly the attitude that led to the concept of 7-litre (500ci) shopping cars in the early '70s. Oil was $3/barrel, petrol 25cents a gallon. Iron was heavy, but cheap. Then things changed. Oil quadrupled in price over night--and stayed there. The world panicked. Over the next few years the price rose again to the unimaginable price of $38/barrel.

        Now look at us. The price of oil is (or was recently) $55/barrel. Depending upon which bunch of scientists or lobbyists you choose to believe, we're all about to bake, freeze or drown. Probably all three.

        No, I don't expect the price of silicon to quadruple, but making chips costs energy. Using chips costs energy(*) and energy isn't going to get cheaper any time soon. If ever. Using more and Moore powerful chips, and Moore and more of them, as an expedient solution to writing code that is unnecessarilly wasteful. Ie. 50 times slower:

        #! perl -slw use strict; use POSIX qw[ strftime ]; use Math::BigInt; use Date::Calc qw/Add_Delta_Days/; use Benchmark qw[ cmpthese ]; sub holli { return POSIX::strftime( "%Y-%m-%d", localtime( ( $_[0] / 10000000 ) - 11644473600 ) ); } sub yours { my $loginTime = Math::BigInt->new( $_[ 0 ] ); $loginTime = $loginTime / (60 * 10000000 ); # 60 seconds in a min +ute! $loginTime = $loginTime / 1440; my ($year,$month,$day) = Add_Delta_Days( 1601, 1, 1, $loginTime ); return "$year-$month-$day\n"; } our $lastLoginTime = '127912653523035916'; cmpthese -1, { yours => q[ my $dateStr = yours( $lastLoginTime ); ], holli => q[ my $dateStr = holli( $lastLoginTime ); ], } __END__ holli: 2006-05-05 yours: 2006-5-5 c:\test>junk8 Rate yours holli yours 3150/s -- -98% holli 161606/s 5030% --

        Just doesn't make sense. Moore is going the way of $3/barrel oil any day now.

        For this one routine, for one date, it's neither here nor there. But when you start processing a few hundred users on each of a few tens or hundreds of servers, it will add up. If every other routine you write is equally as inefficient, then you (or those that make use of your code), will soon need a bigger machine, or a cluster of them. If you or your customers are Google-like, then you need a few thousand extra, more powerful machines. And so it goes.

        When someone knocks on your front door, do you go to the back door and walk all the way around to the front to see who it is? Efficiency is simply logical.

        (*)Update: For those that consider that worrying about the power consumption of servers is stupid. Computer servers are estimated to have consumed 1.2% of all the energy used in the USA during 2006.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Calculating lastLoginTimeStamp from Active Directory
by holli (Abbot) on Feb 16, 2007 at 10:50 UTC
    print POSIX::strftime( "%Y-%m-%d", localtime(($lastLoginTime/10000000)-11644473600) ); :-)


    holli, /regexed monk/
      Use Time::NT

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://600396]
Approved by shmem
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (6)
As of 2024-04-18 13:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found