- Dwarfsoft [GPA] - http://www.dwarfsoft.com/blog -

Last Login Time

I have recently been having a look into determining the Last Login Time of a user for a BGInfo implementation. Firstly I had a look at the getCurrentUserLastLoginTime script [1] suggested for use with BGInfo. The limitation of this script, however, is that it will reset the login time to the last time the Windows login box was Authenticated against, which also includes the time that the workstation was unlocked.

In order to maintain current BGInfo information the implementation is running periodically, so this is unnacceptable. Therefore I had to work to resolve the issue manually. As I have had a fair bit of experience with Windows Profiles recently (see the last blog post [2]) I was familiar with the ProfileLoadTimeHigh and ProfileLoadTimeLow registry keys in the ProfileList. So I set out to determine how to actually use these to determine the login time. I first wrote some code to get the User SID based on the users “%userdomain%” and “%username%”:

DIM oNet, strComputerName, strUserName, strUserDomain
SET oNet = CreateObject("WScript.Network")
strComputerName = oNet.Computername
strUserName = oNet.UserName
strUserDomain = oNet.UserDomain
SET oNet = nothing

Set WMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

SubKey = ""

Set wmiCol = WMI.ExecQuery ("SELECT Domain, Name, SID FROM Win32_Account where Name="""&strUserName&""" And Domain="""&strUserDomain&"""")
For each wmiItem in wmiCol
  SubKey = wmiItem.SID
  Exit For
Next

So I set Subkey to be the String SID of the user, which I could then use to read the ProfileLoadTimeHigh and ProfileLoadTimeLow keys for the correct profile. I used the basic script from MyITForum [3], however this failed to take into account the timezone on the local machine. Therefore the first thing I needed to do was get the users timezone.

tz = 0
For Each os In GetObject("winmgmts:").InstancesOf ("Win32_OperatingSystem")
  tz = os.CurrentTimeZone
  Exit For  
Next

Then I integrated the Timezone offset (in minutes) into the original ProfileLoadTime script [3].

Const HKEY_LOCAL_MACHINE = &H80000002

strReturn = ""

Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv"  )
strKeyPath = "SOFTWARE\MICROSOFT\Windows NT\CurrentVersion\ProfileList\" & SubKey 

strValueName = "ProfileLoadTimeHigh"
Return = objReg.GetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,lngHighValue)
strValueName = "ProfileLoadTimeLow"
Return = objReg.GetDWORDValue(HKEY_LOCAL_MACHINE,strKeyPath,strValueName,lngLowValue)
If typename(lngHighValue) <> "Null" then
  NanoSecs = (lngHighValue * 2 ^ 32 + lngLowValue)
  '' /* Returns time in Workstation Timezone */
  DT = #1/1/1601# + (NanoSecs / 600000000 / 1440) + (tz / 1440)
  strReturn = CDate(DT)
End if

Finally the output is printed as per a standard BGInfo script

On Error Resume Next
	call WScript.Echo(strReturn)	'for cmd line
	call Echo(strReturn)	'for BGInfo
on error goto 0

This works for Power Users as well, which the original script did not (due to permissions issues). Hope this helped you in some way 😉

Cheers, Chris.