Click here to Skip to main content
15,886,617 members
Articles / Programming Languages / C#
Article

Server-restart-necessary reminder service

Rate me:
Please Sign up or sign in to vote.
4.09/5 (4 votes)
27 Mar 2007CPOL5 min read 31.9K   458   27   2
This service sends an email to the user when a server restart because of a Windows update is necessary.

Introduction

In a domain with many servers, automatic updates using the Windows update agent have become standard. By these means, administrators can deploy new updates with a minimum effort to all servers, and the servers can handle the update process automatically by themselves, including a possible restart after the patch. Such automatic restarts can be unwanted, for instance, when running a long-term calculation on the given machine. A possible solution would be to configure the machine in such a way that it does not restart automatically, but that would leave your machine vulnerable until you log in and get the message that the machine has to be rebooted.

We propose as an alternative solution the creation of an instant message, which informs you that the server needs a reboot, enabling you to react quickly by logging on to the machine and deciding whether the restart is appropriate now or later.

Architecture

The goal of the service is the automatic generation of an email whenever the automatic update needs to reboot the server. To achieve this, it is necessary to notice that the Windows update agent has installed a patch and wants the machine to reboot. The agent writes its activities to the Windows event log, thus we can monitor the event log for new entries from the Windows update agent. The constraints on the implementation are the following: firstly, it has to be a Windows service to run without a user being logged on; secondly, it needs to monitor the event log to recognize events from the update agent; and thirdly, it has to send an email to a given address.

Using the Code

Windows Service

Visual Studio 2005 allows fast implementation of Windows Services. Create a new project and use the 'Windows Service' Template from the Visual C# / Windows category. Visual Studio will create a project body that runs a Windows Service: we just need to implement the functionality. In addition to the service functionality, we will add a Windows form for debugging purposes, since services can't be started from the studio. In the startup class, 'Program.cs', we add a differentiation between the debug and release mode to call the service automatically or from the Windows form depending on the running context.

C#
static void Main()
{
  ServiceBase[] ServicesToRun;

  ServicesToRun = new ServiceBase[] { new ServiceBody() };

#if DEBUG
  // start the winform to test our application

  System.Windows.Forms.Application.Run(new TestForm());
#else
  // this starts our service

  ServiceBase.Run(ServicesToRun);
#endif

The functionality of the service class (called 'ServiceBody') consists of starting the monitoring of the Windows event log. This is implemented by the function 'OnStart' which is created by Visual Studio. In order to allow a certain degree of configurability, we first read some configuration info before starting the eventlog-watcher. In case of a reconfiguration of the running service, the service needs to be restarted. In order to apply changes without restart, the configuration needs to be read whenever an event is written to the event log. The next step consists of initializing the eventlog-watcher using the configuration values and starting it.

C#
protected override void OnStart(string[] args)
{
  // read the properties from app.config

  // if you change settings, the service needs to be restarted

  Properties.Settings _mySettings = 
    new RestartReminderService.Properties.Settings();

  // initialize the eventlog watcher with the loaded settings

  _myLogger = new EventLogger(_mySettings.LogNameToWatch, 
                              _mySettings.SourceNameToWatch, 
                              _mySettings.MailServerName, 
                              _mySettings.MailSender, 
                              _mySettings.MailReceiver, 
                              _mySettings.MailTitle);
  // start the eventlog watcher

  _myLogger.StartLogging();
}

Eventlog Watcher

To recognize new entries in the event log, we first need to subscribe to the event that is fired when a new entry is created. The name of this event is EntryWrittenEventHandler, and it can be found in the System.Diagnostic namespace. It demands one parameter, the name of the function to be called when the event fires. I have named this function _myLog_EntryWritten, yet any other name would do. Make sure that the event log receives event notification, by setting EnableRaisingEvents to true.

C#
public void StartLogging()
{
  EventLog _myLog = new EventLog(_logName);

  _myLog.EntryWritten += new EntryWrittenEventHandler(_myLog_EntryWritten);
  _myLog.EnableRaisingEvents = true;
}

The method _myLog_EntryWritten needs to filter all the events fired from new entries to the event log, since the service should react exclusively to entries from the Windows update agent. The property Entry.Source from the Eventargumentvariable, which is passed on to _myLog_EntryWritten, contains the source of the entry, enabling us to infer whether the entry is from the update agent or not. If it is, the mailer class is called, and receives the event message and the name of the machine, for the purpose of recognizing the updated machine when we get the mail.

C#
void _myLog_EntryWritten(object sender, EntryWrittenEventArgs e)
{
  // we only want to react to events from a certain source

  if (e.Entry.Source.Equals(_logSource))
  {
    // send a mail, to inform the receiver, that an event has happend

    MailSender _myMail = new MailSender();
    _myMail.SendMail(_smtpServer, 
                     _from, 
                     _to, 
                     _title, 
                     e.Entry.MachineName + ": " + e.Entry.Message);
  }
}

The used parameters are written to state variables during the instantiation of our eventlog-watcher class.

Mail Sender

To send an email automatically, the System.Net.Mail namespace must be included. It contains a class 'SmtpClient' that can be used to send the email. To keep things simple, we do not authenticate ourselves to the server. If you don't have access to an SMTP-server without authentication, you will need to add the authentication to the code. There are just two lines to send the mail, and I have added a simple error logging function, in case something is mis-configured.

C#
try
{
  SmtpClient _mySmtpClient = new SmtpClient(smptServer);
  _mySmtpClient.Send(from, to, title, message);
}
catch (Exception e)
{
  logging.logger.ErrorRoutine(e,
                              "smtpServer: " + smptServer + 
                              ", from: " + from + 
                              ", to: " + to + 
                              ", title: " + title + 
                              ", message: " + message);
}

Installation

The installation of a service needs a class which is derived from the class 'Installer'. I use a class from John Storer, modified to fit to the project.

C#
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
{
  /// <summary>

  /// Public Constructor for WindowsServiceInstaller.

  /// - Put all of your Initialization code here.

  /// </summary>

  public WindowsServiceInstaller()
  {
    ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
    ServiceInstaller serviceInstaller = new ServiceInstaller();

    //# Service Account Information

    serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
    serviceProcessInstaller.Username = null;
    serviceProcessInstaller.Password = null;

    //# Service Information

    serviceInstaller.DisplayName = "RestartReminder";
    serviceInstaller.StartType = ServiceStartMode.Automatic;

    serviceInstaller.ServiceName = "RestartReminderService";

    this.Installers.Add(serviceProcessInstaller);
    this.Installers.Add(serviceInstaller);
  }
}

Put the compiled project with a batch file for installation (and de-installation) to the server to monitor. Configure the service via editing the RestartReminderService.exe.config. You can set the mail server, your mail address, and so on. Finally, run the following batch installation file (for uninstalling, use the switch /u):

@ECHO OFF

REM The following directory is for .NET 2.0
set DOTNETFX2=%SystemRoot%\Microsoft.NET\Framework\v2.0.50727
set PATH=%PATH%;%DOTNETFX2%

echo Installing WindowsService...
echo ---------------------------------------------------
InstallUtil /i RestartReminderService.exe
echo ---------------------------------------------------
echo Done.

The process is now configured to run automatically after system startup. But it doesn't start up automatically after the installation, and therefore it needs to be started manually once.

Conclusion

The service introduced above is a very simple, straightforward one, which incorporates three aspects: Windows Service programming, eventlog-monitoring, and mailing. These aspects are used to inform the user that a server machine needs to be rebooted, because of patch-installation by the Windows update agent. Via configuration, this service is able to monitor and inform the user about any event source that writes entries in the event log.

The author would like to thank the following people for their great articles here on CodeProject that form the basis for his solution:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalservice will hang during load under Windows 2000 Pin
avnersimon9-Apr-07 10:09
avnersimon9-Apr-07 10:09 
If you are using the ServiceBase class from the .NET library,
and also set the CanHandleSessionChangeEvent = true,
your service will hang during load under Windows 2000.

avnersimon
GeneralRe: service will hang during load under Windows 2000 Pin
Aaginor16-Apr-07 23:13
Aaginor16-Apr-07 23:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.