Become a Columnist Microsoft Exchange Site Microsoft Support SiteMSDN Exchange Site

   

Subscribe to OutlookExchange
Anderson Patricio
Ann Mc Donough
Bob Spurzem
Brian Veal
Catherine Creary
Cherry Beado
Colin Janssen
Collins Timothy Mutesaria
Drew Nicholson
Fred Volking
Glen Scales
Goran Husman
Guy Thomas
Henrik Walther
Jason Sherry
Jayme Bowers
John Young
Joyce Tang
Justin Braun
Konstantin Zheludev
Kristina Waters
Kuang Zhang
Mahmoud Magdy
Martin Tuip
Michael Dong
Michele Deo
Mitch Tulloch
Nicolas Blank
Pavel Nagaev
Ragnar Harper
Ricardo Silva
Richard Wakeman
Russ Iuliano
Santhosh Hanumanthappa
Steve Bryant
Steve Craig
Todd Walker
Tracey J. Rosenblath
 
 

Instant Messaging State Logging Script

Introduction                      Download script
    One of the main things lacking in the current version of IM is the lack of decent logging features to capture information about use of the system. Currently you can use IIS logging to record protocol conversations and Perfmon to record the load and number of users using the system but getting statistics such as which users are logging on and how long they are staying online etc are not available . What this script has been designed to do is scan your active directory for all the users that have an IM address and then check the IM status of that user and record the information in a log file. This information can then be used to look at which users logged on how long they where online, offline, busy etc. You could even use this information to look at the actually amount of time each pc is being used in your network. for example when the user is working normally on their PC their IM status will be available if the user steps away from their PC or doesn't use it for a period of 20 minutes the user's status will be set automatically to away. These features can allow you to gather some unique types of information about use of computers on your network.

How it works
 
   This script is divided into three major sections and uses functions to deal with the parts of the script that need to be called multiple times.

Front-end

    The front-end of this code sets up the date and time functions that are used in the log file, I prefer using a serial date format as I find it more usable when writing scripts. It also creates the file system object for the log file and opens the log file or creates a new one if it doesn't exist.

Active Directory Query

   
Because users in Exchange 2000 are not usually located all in the same container or OU in Active directory this part of the script is designed to recursively look though all the OU's and the user container in active directory for user objects with an IM address's. It uses functions to search through  OU's  and transverse each child OU to find all active directory user accounts. Once a user is found with an IM address the IM status query section of the code is performed

sRootDomain = "DC=AD1,DC=NOTMYNETWORK,DC=NET,DC=AU"  ' Put you AD DNS name in here
Set oRootDomain = GetObject("LDAP://" & sRootDomain)
oRootDomain.Filter = Array("organizationalUnit")
seachou(oRootDomain)
searchcont(oRootDomain)
Function seachou(oOusear)
For Each oOU In oOusear
	if oOU.Class = "user" then
			if oOU.msExchIMAddress <> "" then
				imlogonname = oOU.msExchIMAddress
				username = oOu.SamAccountName
				writ = imcheckstate(imlogonname, username)
			End If
	
	End If
	oOU.Filter = Array("user")
    	For Each oUser In oOU
		if oUser.Class = "user" then
			if oUser.msExchIMAddress <> "" then
				imlogonname = oUser.msExchIMAddress
				username = oUser.SamAccountName
				writ = imcheckstate(imlogonname, username)
			End If
		End If
	Next
	oOu.Filter = Array("organizationalUnit")
	For Each oChild In oOU
		seachou(oChild)
	next 
Next
end function
Function searchcont(oScont)
oScont.Filter = Array("container")
For Each oContainer In oScont
	oContainer.Filter = Array("user")
    		For Each oUser In oContainer
			if oUser.Class = "user" then
				if oUser.msExchIMAddress <> "" then
					imlogonname = oUser.msExchIMAddress
					username = oUser.SamAccountName
					writ = imcheckstate(imlogonname, username)
				End If
			End If
		Next
Next

IM Status Query

    To retrieve the IM status of an Exchange user account the IM runtime components are used. (The Exchange 2000 Instant Messaging Client SDK Runtime Components which can be download from http://www.microsoft.com/downloads/release.asp?ReleaseID=24779 or from the Exchange SDK.)

The first section of code creates the IMhost object and then logs onto the IM Server

Set oIMApp = CreateObject("MSExchangeIM.MSIMHost")
Set oIMServ = oIMApp.CreateContext("Default", 0)
strtest = Array("newb1@exbend","newb1","pass","ad1")
oIMServ.logon strtest

    The first  two lines creates an instance of the MSIMHost class and an interface pointer to this class. The next  two lines provides a logon to Instant messaging through calling the logon method of the newly created  MSIMHost object. The parameters passed to this method can vary depending on your requirements. In the above code i have passed the IMlogon, username, password and domain name. You can however choose to pass only the logon name and as long as the user executing the code has rights to logon to the IM account (and your using NTLM authentication) it will works fine .     The imcheckstate() function is called by the active directory query section and  performs the IM status queries. It does this by first adding the user as an IM contact, this notifies the Exchange IM server that this user has subscribed to IM status of the added user. It then uses the .state method to retrieve the IM state of the user and then writes this information to the log file.

Function imcheckstate(imlogonname1, username1)
on error resume next
set oIMsession = oIMServ.Createcontact(imlogonname1)
Set oIMList = oIMServ.List ("$$Messenger\Contact")
oIMList.Add oIMsession
nfile.write qdat & "," & ltime & "," & imlogonname1 & "," & username1 & "," & oIMsession.state & vbCrLf
end Function

The IM state is returned as a number and this number corresponds to the instant messaging state the following is a table of numbers to states (this is available in the exchange SDK) .

IM_STATE_UNKNOWN 0x0000 The state of the local or remote client is unknown.
IM_STATE_OFFLINE 0x0001 The local or remote client is not connected to a server.
IM_STATE_ONLINE 0x0002 The local or remote client is connected to a server.
IM_STATE_INVISIBLE 0x0006 The local or remote client is connected to a server but invisible to other users.
IM_STATE_BUSY 0x000A The local or remote client is connected to a server and in a user-selected state of Busy.
IM_STATE_BE_RIGHT_BACK 0x000E The local or remote client is in a user-selected state of Be Right Back.
IM_STATE_IDLE 0x0012 The local or remote client has not detected mouse or keyboard input on the computer for a determined time. The user is most likely away from the computer. Whether to transmit the idle state and the idle time threshold are based on the screen saver.
IM_STATE_AWAY 0x0022 The local or remote client user has stepped away from the computer (a user-selected state).
IM_STATE_ON_THE_PHONE 0x0032 The local or remote client user is in a user-selected state of On The Phone.
IM_STATE_OUT_TO_LUNCH 0x0042 The local or remote client user is in a user-selected state of Out To Lunch.
IM_STATE_LOCAL_FINDING_SERVER 0x0100 The local client is attempting to find the server.
IM_STATE_LOCAL_CONNECTING_TO_SERVER 0x0200 The local client is connecting to the server.
IM_STATE_LOCAL_SYNCHRONIZING_WITH_SERVER 0x0300 The local client is synchronizing with the server.
IM_STATE_LOCAL_DISCONNECTING_FROM_SERVER 0x0400 The local client is disconnecting from the server.

Implementing and running this code
   
To implement and run this code you need to first customise certain parts of the code with your own Active directory and log file preferences.

logfile = "c:\imlogs\" & qdat & ".log" ' this sets the log file location (directory needs to exist or the script wont work)

strtest = Array("newb2@exbend","newb2","pass","ad1") ' This is the IM user that is used to query status information you need to sets this to your own user

sRootDomain = "DC=AD1,DC=NOTMYNETWORK,DC=NET,DC=AU" ' You need to set this to your own AD DNS domain name

    To run this code you can use the task scheduler under Windows 2000 and schedule it to run at your desired sample interval (usually around 10-20 minutes is a good sample interval). Because it uses a LDAP reference you can run the code on any machine that is a member of your domain that has the runtime components installed,  you do need to make sure that the user its running under has privileges to perform the active directory queries (or just use a domain admin)

What do you end up with

    You end up with a log file that looks simular to below (this can be customised) but basically its date,time,IMaddress,username,imstate the Imstate is present as a number (see table above)

20020404,10:21,administrator@exbend,Administrator,2

This entry represents that the user Administrator is online eg state 2

    You can then take these log files and use something such as DTS with SQL7 to import the csv files into a SQL database and then use crystal reports or some other reporting tools to create reports based on this data.

 Download script


Disclaimer: Your use of the information contained in these pages is at your sole risk. All information on these pages is provided "as is", without any warranty, whether express or implied, of its accuracy, completeness, fitness for a particular purpose, title or non-infringement, and none of the third-party products or information mentioned in the work are authored, recommended, supported or guaranteed by Stephen Bryant or Pro Exchange. OutlookExchange.Com, Stephen Bryant and Pro Exchange shall not be liable for any damages you may sustain by using this information, whether direct, indirect, special, incidental or consequential, even if it has been advised of the possibility of such damages.

Copyright Stephen Bryant 2008