Records System Session Events Triggered Time Like Shutdown, Lock/Unlock, LogOn/LogOff Using Windows Service

This blog explains how to record system events such as Windows Lock/Unlock, LogOn/LogOff, Shutdown in C#.

This project is a Windows Service in which we will see how to record some system events. After that, we will see how to install/register the Services and run it locally.
  1. Create a new Windows Service project in Visual Studio. 
  2. Note you'll see Service1.cs file by default added to project.
  3. Open that you will see the designer view.
  4. Now switch to the code view by pressing F7 or click on link switch to code view.
  5. In code, you'll notice there are two methods by default OnStart() and OnStop(). Generally, these two methods are called when Service starts and Stops respectively. And we can use this to perform any operation during the service start or stop like record a log that service started and stopped.
  6. Now we need to work on System Session related Events like logon/logoff etc. How can we achieve it?
  7. We need to override OnSessionChange() method to the class. 
  8. As you can see it has a parameter called SessionChangeDescription. This provides us the reason for the change of session. Obviously, your next question is what kind of reasons are these? The reason states why OnSessionChange is triggered which may due to SessionLogon, RemoteConnect, SessionLock,etc.
So, how can we log the datetime when does this event happen? For that, we will create a switch-case statement as shown in the code below.
  1. protected override void OnSessionChange(SessionChangeDescription changeDescription)    
  2.         {    
  3.             if (!File.Exists(logPath))    
  4.             {    
  5.                 File.Create(logPath).Close();    
  6.             }    
  7.     
  8.             switch (changeDescription.Reason)    
  9.             {    
  10.                 case SessionChangeReason.SessionLogon:    
  11.                     File.AppendAllText(logPath, ">>> System Log On Time: \t " + DateTime.Now + Environment.NewLine);    
  12.                     break;    
  13.                 case SessionChangeReason.SessionLogoff:    
  14.                     File.AppendAllText(logPath, ">>> System Log Off Time: \t " + DateTime.Now + Environment.NewLine);    
  15.                     break;    
  16.                 case SessionChangeReason.RemoteConnect:    
  17.                     File.AppendAllText(logPath, ">>> System Remote Connect Time: \t " + DateTime.Now + Environment.NewLine);    
  18.                     break;    
  19.                 case SessionChangeReason.RemoteDisconnect:    
  20.                     File.AppendAllText(logPath, ">>> System Remote Disconnect Time: \t " + DateTime.Now + Environment.NewLine);    
  21.                     break;    
  22.                 case SessionChangeReason.SessionLock:    
  23.                     File.AppendAllText(logPath, ">>> System Locked Time: \t" + DateTime.Now + Environment.NewLine);    
  24.                     break;    
  25.                 case SessionChangeReason.SessionUnlock:    
  26.                     File.AppendAllText(logPath, ">>> System Unlocked Time: \t " + DateTime.Now + Environment.NewLine);    
  27.                     break;    
  28.                 default:    
  29.                     break;    
  30.             }    
  31.         }    
Note: I've referenced System.IO namespace and provided logPath value to record the logs in one location.
 
My Service Class
  1. public partial class SysService : ServiceBase    
  2.     {    
  3.         string logPath = "D:\\SystemLogs.txt";    
  4.     
  5.         public SysService()    
  6.         {    
  7.             InitializeComponent();    
  8.         }    
  9.     
  10.         protected override void OnStart(string[] args)    
  11.         {    
  12.             if (!File.Exists(logPath))    
  13.             {    
  14.                 File.Create(logPath).Close();    
  15.             }    
  16.     
  17.             File.AppendAllText(logPath, Environment.NewLine + ">>>> Datetime:" + DateTime.Now + ">>> Service Started");    
  18.     
  19.               
  20.         }    
  21.     
  22.         protected override void OnSessionChange(SessionChangeDescription changeDescription)    
  23.         {    
  24.             if (!File.Exists(logPath))    
  25.             {    
  26.                 File.Create(logPath).Close();    
  27.             }    
  28.     
  29.             switch (changeDescription.Reason)    
  30.             {    
  31.                 case SessionChangeReason.SessionLogon:    
  32.                     File.AppendAllText(logPath, ">>> System Log On Time: \t " + DateTime.Now + Environment.NewLine);    
  33.                     break;    
  34.                 case SessionChangeReason.SessionLogoff:    
  35.                     File.AppendAllText(logPath, ">>> System Log Off Time: \t " + DateTime.Now + Environment.NewLine);    
  36.                     break;    
  37.                 case SessionChangeReason.RemoteConnect:    
  38.                     File.AppendAllText(logPath, ">>> System Remote Connect Time: \t " + DateTime.Now + Environment.NewLine);    
  39.                     break;    
  40.                 case SessionChangeReason.RemoteDisconnect:    
  41.                     File.AppendAllText(logPath, ">>> System Remote Disconnect Time: \t " + DateTime.Now + Environment.NewLine);    
  42.                     break;    
  43.                 case SessionChangeReason.SessionLock:    
  44.                     File.AppendAllText(logPath, ">>> System Locked Time: \t" + DateTime.Now + Environment.NewLine);    
  45.                     break;    
  46.                 case SessionChangeReason.SessionUnlock:    
  47.                     File.AppendAllText(logPath, ">>> System Unlocked Time: \t " + DateTime.Now + Environment.NewLine);    
  48.                     break;    
  49.                 default:    
  50.                     break;    
  51.             }    
  52.         }    
  53.         protected override void OnShutdown()    
  54.         {    
  55.             if (!File.Exists(logPath))    
  56.             {    
  57.                 File.Create(logPath).Close();    
  58.             }    
  59.             File.AppendAllText(logPath, ">>> System Turn Off Time: \n " + DateTime.Now + Environment.NewLine);    
  60.         }    
  61.     
  62.         protected override void OnStop()    
  63.         {    
  64.             if (!File.Exists(logPath))    
  65.             {    
  66.                 File.Create(logPath).Close();    
  67.             }    
  68.     
  69.             File.AppendAllText(logPath, Environment.NewLine + ">>>> Datetime:" + DateTime.Now + ">>> Service Stopped");    
  70.     
  71.         }    
  72.     }   
Now, what you thing would this run as expected? No, it would required two properties need to be changed. Go to Service.cs design file properties and update below highlighted 2 properties value to true. 
 
Basically, this allows the service to handle SessionChange event.
 
Thats it now we have created a service. Now how can we Install this service.
  1. When we created a service lets build it once. Now assembly package(.exe) would be generated with the service name which ever you've given.
  2. Open VS Dev command prompt (Administrator) and navigate to your project assembly package. Now type InstallUtil.exe <path to this exe in bin/debug folder/{assembly name}> and hit enter as shown below. And service would be installed. To uninstall the service type InstallUtil.exe /u <path to this exe in bin/debug folder> and hit enter.  
Once the service is installed, you can navigate to Services.msc and start you service. And see the output in SystemLogs.txt file where you located the path.
 
Hope you liked this :)
 
If you're new to Windows Services, read tutorial: Create a Windows Service in C#