Monday, March 9, 2009

Are you free, Mr. Kay?

At the office, we use Exchange.  I've been a fan of Exchange since the first time I administered an Exchange 5.0 server for 200 users.  Now, I work on a team that supports 15,000 users!  Being the third level support for Exchange, the members of my group use Outlook a little more intensely than your typical worker.  But...not everyone. :)

For example, if we're going to be on PTO, aside from letting our supervisor and HR know, we have to let the team know.  We could easily setup a team calendar to handle time off information, but we find it's just easier to send each other all day appointments with titles like "Tony - PTO".  What we normally do is set the busy information to "Free" before we send it out so that it doesn't block off our coworkers days.  Sometimes, though, folks forget to do that and I'll end up with entire weeks blocked off and project managers screaming because they can't find any free time in my schedule.  Deciding today I'd had enough, I wrote a little program to take care of this for me.  What the below VB does is open my Outlook calendar and iterate through all of the items in there.  It checks the subject line, and if it contains "PTO", it then checks to make sure it's set to free (BusyStatus of 0).  If not, it changes it, saves it and then writes the subject/free/busy again to confirm it's been changed. 

Imports Outlook = Microsoft.Office.Interop.Outlook

Module Module1

    Sub Main()
        Dim objOLApp As Outlook.Application
        Dim objOLNS As Outlook.NameSpace
        Dim objCalendar As Outlook.Folder
        Dim colItems As Outlook.Items
        Dim objappointment As Object

        objOLApp = New Outlook.Application
        objOLNS = objOLApp.GetNamespace("MAPI")
        objOLNS.Logon("", "", False, True)
        objCalendar = objOLNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar)
        colItems = objCalendar.Items
        For Each objappointment In colItems
            If InStr(objappointment.Subject, "PTO") Then
                If objappointment.BusyStatus <> 0 Then
                    Console.WriteLine(objappointment.Subject & " " & objappointment.BusyStatus)
                    objappointment.BusyStatus = Outlook.OlBusyStatus.olFree
                    objappointment.Save()
                    Console.WriteLine(objappointment.Subject & " " & objappointment.BusyStatus)
                End If
            End If
        Next
    End Sub

End Module


It's not the most efficient code, I know.  But, it went through my calendar in about 30 seconds and changed a few hundred entries.  I had planned on using it just this once, but it might be a good thing to schedule to run once a week or so.  Now, I have LOTS of free time for my PMs to fill up!  Oh, wait, that might not be a good thing.... :)


Thursday, March 5, 2009

Mining event logs for useful information

We're having an issue where randomly users will be disconnected from their Citrix session.  It doesn't happen a lot, but on the aggregate it's becoming a nuisance for our user community.  Unfortunately, we don't get good information from our users to help pinpoint the issue.  When we ask them to try and track the times it happens, we'll get one or two notices for a day or two and then it dwindles off.  In perusing the event logs, I found that each disconnect is actually logged as an event from the source "Metaframe" with an EventID of 9007.  The message of the event contains the user name. 

So, if I could write a utility that will cull the useful data from the logs, I wouldt need to rely on users.  I can find the exact date and time of each disconnect and with the help of our Network team, we might be able to pinpoint where the issue actually lies.   So, to that end I did a little research as I'm familiar with reading frmo the eventlogs with VBscript, but I'm trying to do more with VB.net since I can use the VB 2008 Express Edition for free.  The first issue I encountered was that pulling EventIDs is a deprecated propert, and I had to use the EventLog object's InstanceID property instead.  The results recieved from this property need to have the top two bits masked off in order to get the EventID.   That's what's going on in the "intEventID = objentry.InstanceID And &HFFFFFF" line:

    Public Sub ListEventLog()
        Dim objLog = New EventLog()
        Dim intEventID As Integer
        Dim strUsername(), strEventMessage, strDate, strTime, strDateTime() As String

        objLog.Log = "System"
        For Each objentry In objLog.Entries
            intEventID = objentry.InstanceID And &HFFFFFF
            If intEventID = 9007 Then
                strEventMessage = objentry.Message
                strUsername = strEventMessage.Split("\")
                strDateTime = Split(objentry.TimeGenerated, " ")
                strDate = strDateTime(0)
                strTime = strDateTime(1) & " " & strDateTime(2)
                Console.WriteLine(strDate & "," & strTime & "," & strUsername(1))
            End If
        Next
    End Sub

Once compiled, you simply run this utility piping the output to a text file.  You then have a nice CSV you can pull up in Excel to process the data with.