We wanted to create a way to log information about a user's session to a central logfile (by "user's session", I mean the time between logon and logoff) to aid in troubleshooting, and also to easily track what computers users are using and for how long.
While there are probably some good software packages out there that can do this, we thought it shouldn't be too hard to do with some VBScript snippets taken from around the internet. And it wasn't either!
By running a script at logon and logoff (using Group Policy), we were able to gather a wealth of information (which was still really only scratching the surface of what is possible) about each users session which is then logged to a CSV file on a (hidden) network share*.
We are currently logging the following information to our CSV file:
- Logon Date
- Logon Time
- Username
- Domain
- User CN
- User Groups
- Logon Server
- IP Address
- Comp. Name
- Comp. Manufacturer
- Comp. Model
- OS Ver.
- Service Pack Number
- Logon Free Phys. Memory
- Logon CPU Load %
- CPU Model
- Last Boot Time
- Uptime
- Logoff Date
- Logoff Time
- Session Duration (Secs)
- Session Duration
- Logoff Free Phys. Memory
- Logoff CPU Load %
To date, these scripts have produced information that has helped make decisions about the future of certain groups of computers (based on the usage rate), and identify some behavioural issues (some on request, and others that had been obviated by the data itself).
The scripts we're using are as follows (click the links for a neater version)**:
Run at logon
(This script collects information as it's reported at the time of logon and writes it to a temporary file in the user's temp folder)
Dim vaSessionData(17)
'Get date and time.
vaSessionData(0)=Date
vaSessionData(1)=Time
'Get user and domain.
Dim objNet
On Error Resume Next
'In case we fail to create object then display our custom error
Set objNet = CreateObject("WScript.NetWork")
If Err.Number <> 0 Then 'If error occured then display notice
MsgBox "Don't be Shy." & vbCRLF &_
"Do not press ""No"" If your browser warns you."
Document.Location = "UserInfo.html"
'Place the Name of the document.
'It will display again
End if
vaSessionData(2)=objNet.UserName
vaSessionData(3)=objNet.UserDomain
Set objNet = Nothing 'Destroy the Object to free the Memory
'Get the users OU.
On Error Resume Next
Dim objSysInfo, objLuser
Set objSysInfo = CreateObject("ADSystemInfo")
Set objLuser = GetObject("LDAP://" & objSysInfo.UserName)
vaSessionData(4)="""" & objLuser.distinguishedName & """"
'Get the logged on users group memberships.
Dim objNetwork, strDomain, strUser, objUser, objGroup, strGroupMemberships
Set objNetwork = CreateObject("WScript.Network")
strDomain = objNetwork.UserDomain
strUser = objNetwork.UserName
Set objUser = GetObject("WinNT://" & strDomain & "/" & strUser)
For Each objGroup In objUser.Groups
strGroupMemberships = strGroupMemberships & objGroup.Name & ","
Next
vaSessionData(5)="""" & strGroupMemberships & """"
'Get the logon server.
Set objWshShell = CreateObject("Wscript.Shell")
strLogonServer = objWshShell.ExpandEnvironmentStrings("%Logonserver%")
vaSessionData(6)=strLogonServer
'Get IP addresses from all DHCPd interfaces.
strQuery = "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE MACAddress > ''"
Set objWMIService = GetObject( "winmgmts://./root/CIMV2" )
Set colItems = objWMIService.ExecQuery( strQuery, "WQL", 48 )
For Each objItem In colItems
If IsArray( objItem.IPAddress ) Then
If UBound( objItem.IPAddress ) = 0 Then
strIP = "IP Address: " & objItem.IPAddress(0)
Else
strIP = Join( objItem.IPAddress, "," )
End If
End If
Next
vaSessionData(7)="""" & strIP & """"
'Get some useful local computer information
strComputer = "."
Set colSettings = objWMIService.ExecQuery _
("Select * from Win32_ComputerSystem")
For Each objComputer in colSettings
vaSessionData(8)=objComputer.Name
vaSessionData(9)=objComputer.Manufacturer
vaSessionData(10)=objComputer.Model
Next
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colSettings = objWMIService.ExecQuery _
("Select * from Win32_OperatingSystem")
For Each objOperatingSystem in colSettings
vaSessionData(11)=objOperatingSystem.Version
vaSessionData(12)=objOperatingSystem.ServicePackMajorVersion & "." & objOperatingSystem.ServicePackMinorVersion
vaSessionData(13)=objOperatingSystem.FreePhysicalMemory
Next
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor")
For Each objItem in colItems
vaSessionData(14)=objItem.LoadPercentage
vaSessionData(15)="""" & objItem.Name & """"
Next
strComputer = "." ' Local computer
set objWMIDateTime = CreateObject("WbemScripting.SWbemDateTime")
set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
set colOS = objWMI.InstancesOf("Win32_OperatingSystem")
for each objOS in colOS
objWMIDateTime.Value = objOS.LastBootUpTime
vaSessionData(16)=objWMIDateTime.GetVarDate
vaSessionData(17)=TimeSpan(objWMIDateTime.GetVarDate,Now)
next
Function TimeSpan(dt1, dt2)
' Function to display the difference between
' 2 dates in hh:mm:ss format
If (isDate(dt1) And IsDate(dt2)) = false Then
TimeSpan = "00:00:00"
Exit Function
End If
seconds = Abs(DateDiff("S", dt1, dt2))
minutes = seconds \ 60
hours = minutes \ 60
minutes = minutes mod 60
seconds = seconds mod 60
if len(hours) = 1 then hours = "0" & hours
TimeSpan = hours & ":" & _
RIGHT("00" & minutes, 2) & ":" & _
RIGHT("00" & seconds, 2)
End Function
JoinedArray=(join(vaSessionData,","))
'Write our to file in users temp dir.
Dim objFileSystem, objOutputFile, objOutputFile2
Dim strOutputFile
Dim strOutputFile2
Set objTemp = WScript.CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2)
strOutputFile = objTemp & "\Session_Info.log"
strOutputFile2 = objTemp & "\Logon_Time.tmp"
Set objFileSystem = CreateObject("Scripting.fileSystemObject")
Set objOutputFile = objFileSystem.CreateTextFile(strOutputFile, TRUE)
Set objOutputFile2 = objFileSystem.CreateTextFile(strOutputFile2, TRUE)
objOutputFile.WriteLine (JoinedArray)
objOutputFile.Close
objOutputFile2.WriteLine (Date & " " & Time)
objOutputFile2.Close
Set objFileSystem = Nothing
'Wscript.Echo "DONE!"
WScript.Quit(0)
Run at Logoff
(This script collects additional information unique at the time of logoff, which is added to the temp file created at logon. Some calculations are done about the total session length, then all the data is appended as one line to the central logfile, in CSV format)
Dim vaEndSessionData(5)
'Get date and time.
vaEndSessionData(0)=Date
vaEndSessionData(1)=Time
strTimeNow = Date & " " & Time
'Get time of logon and calculate difference
Set objTemp = WScript.CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(objTemp & "\Logon_Time.tmp", 1)
strTimeThen = objFile.ReadLine
objFile.Close
intSecsDifferent=DateDiff("s", strTimeThen, strTimeNow)
vaEndSessionData(2)=intSecsDifferent
Function SplitSec(pNumSec)
Dim d, h, m, s
Dim h1, m1
d = int(pNumSec/86400)
h1 = pNumSec - (d * 86400)
h = int(h1/3600)
m1 = h1 - (h * 3600)
m = int(m1/60)
s = m1 - (m * 60)
SplitSec = cStr(d) & "d " & cStr(h) & "h " & cStr(m) & "m " & cStr(s) & "s"
End Function
vaEndSessionData(3)=SplitSec(intSecsDifferent)
'Update some local computer information
strQuery = "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE MACAddress > ''"
Set objWMIService = GetObject( "winmgmts://./root/CIMV2" )
Set colItems = objWMIService.ExecQuery( strQuery, "WQL", 48 )
'Get some useful local computer information
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colSettings = objWMIService.ExecQuery _
("Select * from Win32_OperatingSystem")
For Each objOperatingSystem in colSettings
vaEndSessionData(4)=objOperatingSystem.FreePhysicalMemory
Next
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor")
For Each objItem in colItems
vaEndSessionData(5)=objItem.LoadPercentage
Next
'write out to file and clean up
vJoinedArray=(join(vaEndSessionData,","))
Set objTemp = WScript.CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2)
Set objFSOr = CreateObject("Scripting.FileSystemObject")
Set objFiled = objFSOr.OpenTextFile(objTemp & ".\Session_Info.log", 1)
strLogonInfo = objFiled.ReadLine
objFiled.Close
'Wscript.Echo strLogonInfo & "," & vJoinedArray
strSessionInfo = strLogonInfo & "," & vJoinedArray
Dim objFileSystem, objOutputFile
Dim strOutputFile
strOutputFile = "\\server.domain\share$\logfile.log"
Set objFileSystem = CreateObject("Scripting.fileSystemObject")
Set objOutputFile = objFileSystem.OpenTextFile(strOutputFile, 8)
objOutputFile.WriteLine (strSessionInfo)
objOutputFile.Close
Set objFileSystem = Nothing
Set objTemp = WScript.CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2)
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.DeleteFile(objTemp & "\Session_Info.log")
objFSO.DeleteFile(objTemp & "\Logon_Time.tmp")
WScript.Quit(0)
Finally, the logfile can be searched using a simple text editor, or preferably, dropped into Excel and searched, manipulated and otherwise finessed to draw out the sort of great information that hides in any raw data.
Enjoy!
* This may not be the most secure method of creating the central logfile, some NTFS permissions can be put in place to prevent users accessing the logfile, but ultimately you can never completely secure the share because the user has to be able to write to the file.
** I'll be the first to admit the scipt is ugly. I'm sure people with more scripting skills than me can suggest ways to clean it up. If so, go right ahead.
No comments:
Post a Comment