Setting Up a Custom Event Log Installer with InstallUtil.exe and SharePoint 2010 Feature Receiver

Hi,

If you’ve seen this error message before “The source was not found, but some or all event logs could not be searched. Inaccessible logs: Security.”, you’ll know what I’m taking about. If not, that’s cool. In this blog post, I’ll attempt to show you how to setup a custom Log and have it display in the Windows Event Viewer.

I will break this down to several sections.

Scenario – The reason behind doing this is simple. You want to write to the Windows Event Log from inside of your custom application and you like to follow best practices and be nice about it 🙂 This application can be a Windows Forms application or simply another Web Application or even a custom application living inside of SharePoint. Since my focus been on SharePoint these past few years, I’ll focus on the latter type of application.

Setup – Here’s what I’m going to have. I will create me a SharePoint 2010 Empty project in Visual Studio 2010 deployable in a Farm. I will add a reference to System.Configuration.Install. I will then create a class that inherits from System.Configuration.Install.Installer, place the RunInstallerAttribute on top of it, write few lines of code there. Then I will create a Feature with an event receiver that will eventually run the InstallUtil.exe executable and create the Event Log with its Source for me. To store my installer logs, I’ll create a folder on my C Drive and call it JMH.

CustomInstaller-01

Solution  – Here, I’ve got several parts.

01. CustomInstaller.cs – This is a simple .CS file inside of my project. I added few references to it. System.Configuration.Install, System.ComponentModel, and System.Diagnostics. Here’s the code for it. I removed unused Using statements.

   1: using System.ComponentModel;

   2: 

   3: using System.Configuration.Install;

   4: using System.Diagnostics;

   5: 

   6: namespace JMH.SharePoint.CustomInstaller

   7: {

   8:     /// <summary>

   9:     /// Run InstallUtil tool. Can be found here: C:\Windows\Microsoft.NET\Framework64\v2.0.50727

  10:     /// installutil /LogFile=C:\JMH\EventLogCustomInstaller.InstallLog /AssemblyName "JMH.SharePoint.CustomInstaller"

  11:     /// 

  12:     /// Ref1. http://msdn.microsoft.com/en-us/library/50614e95(VS.85).aspx

  13:     /// Ref2. http://msdn.microsoft.com/en-us/library/system.diagnostics.eventloginstaller(VS.85).aspx

  14:     /// </summary>

  15:     [RunInstallerAttribute(true)]

  16:     public class EventLogCustomInstaller : Installer

  17:     {

  18:         private EventLogInstaller _EventLogCustomInstaller;

  19: 

  20:         public EventLogCustomInstaller()

  21:         {

  22:             // Create an instance of an EventLogInstaller.

  23:             _EventLogCustomInstaller = new EventLogInstaller();

  24: 

  25:             // Set the source name of the event log.

  26:             _EventLogCustomInstaller.Source = "JMH";

  27: 

  28:             // Set the event log that the source writes entries to.

  29:             _EventLogCustomInstaller.Log = "JMH";

  30: 

  31:             // Add myEventLogInstaller to the Installer collection.

  32:             Installers.Add(_EventLogCustomInstaller);

  33:         }

  34: 

  35:         public static void Main()

  36:         {

  37:         }

  38:     }

  39: }

02. JMHCustomInstaller.feature – This is a new Feature I created in my project. The scope is set to Web by default on this. I’ll set Activate On Default to False and Always Force Install to True.

03. JMHCustomInstaller Event Receiver – I added an event receiver to this feature. I removed all the overrides from the class except for the FeatureActivated event. I’d like to use this to initiate the InstallUtil.exe process and create my custom event log. I added few using statements as well: System.Diagnostics, and System.IO. I also changed the namespace. The code is as follows.

   1: using System;

   2: using System.Runtime.InteropServices;

   3: using Microsoft.SharePoint;

   4: 

   5: using System.Diagnostics;

   6: using System.IO;

   7: 

   8: namespace JMH.SharePoint.CustomInstaller

   9: {

  10:     /// <summary>

  11:     /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.

  12:     /// </summary>

  13:     /// <remarks>

  14:     /// The GUID attached to this class may be used during packaging and should not be modified.

  15:     /// </remarks>

  16: 

  17:     [Guid("9c9942de-e851-427f-82d0-5c519e7a7058")]

  18:     public class JMHCustomInstallerEventReceiver : SPFeatureReceiver

  19:     {

  20:         public override void FeatureActivated(SPFeatureReceiverProperties properties)

  21:         {

  22:             //  Do some clean up

  23:             try

  24:             {

  25:                 if (EventLog.SourceExists("JMH"))

  26:                     EventLog.DeleteEventSource("JMH");

  27: 

  28:                 if (EventLog.Exists("JMH"))

  29:                     EventLog.Delete("JMH");

  30:             }

  31:             catch (Exception)

  32:             {

  33:             }

  34: 

  35:             //  Give it a try

  36:             try

  37:             {

  38:                 string installerArguments = String.Format("/LogFile={0} /AssemblyName {1}", @"C:\JMH\JMHCustomInstaller.InstallLog", "\"JMH.SharePoint.CustomInstaller, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0122d41e560c7f87\"");

  39: 

  40:                 ProcessStartInfo processStartInfo = new ProcessStartInfo(@"C:\Windows\Microsoft.NET\Framework64\v2.0.50727\installutil.exe", installerArguments);

  41: 

  42:                 processStartInfo.RedirectStandardOutput = true;

  43:                 processStartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

  44:                 processStartInfo.UseShellExecute = false;

  45: 

  46:                 Process installerProcess = Process.Start(processStartInfo);

  47:                 StreamReader processResults = installerProcess.StandardOutput;

  48: 

  49:                 //  Wait in milliseconds (ms) 1k ms = 1 sec

  50:                 installerProcess.WaitForExit(3000);

  51: 

  52:                 if (installerProcess.HasExited)

  53:                 {

  54:                     EventLog.WriteEntry("JMH", processResults.ReadToEnd());

  55:                 }

  56:             }

  57:             catch (Exception)

  58:             {

  59:                 //  Log error here

  60:             }

  61:         }

  62:     }

  63: }

Notice I’m writing a message to the event log using the source I’ll be creating. This should let us know whether our installer worked or not. See line: EventLog.WriteEntry(“JMH”, processResults.ReadToEnd());

Few things to note:

1. My installer and the feature are all in the same project. My project is not an executable. I am using an Assembly DLL here. So in order for me to load the custom installer file, I have to reference the assembly by its fully qualifying name.

2. I added few lines of code to do some clean up. You may have some trouble installing or loading your custom installer file. If so, ensure that you reset IIS and retract and redeploy the package.

Finally, here’s what we got. We have a new Event Log source and Log file created. We logged our actions in a installer log file. We’re using a SharePoint 2010 feature to do this. Here are some final screen shots.

The after-look of our Visual Studio 2010 solution –

CustomInstaller-02

The installer log file –

CustomInstaller-02

The JMH custom event log –

CustomInstaller-02

References – Here are the references I used to write this blog entry.

MSDN (Event Log Installer) – http://msdn.microsoft.com/en-us/library/system.diagnostics.eventloginstaller(VS.85).aspx

MSDN (InstallUtil.exe) – http://msdn.microsoft.com/en-us/library/50614e95(VS.85).aspx

MSDN (Delete Event Source) – http://msdn.microsoft.com/en-us/library/twdecbsx.aspx

stackoverflow (Returning results from a process) – http://stackoverflow.com/questions/206323/how-to-execute-command-line-in-c-get-std-out-results

Hope this was helpful.

Have a great New Year.

Advertisements

About jharbieh

I'm an IW Solutions Architect with background in requirements gathering, planning, design, architecture, and development (not necessarily in the right order). Currently, my focus is on the Microsoft Cloud, Productivity and Collaboration space. Hope you enjoy what I write about here. Thanks for visiting. Johnny Harbieh
This entry was posted in SharePoint Development. Bookmark the permalink.