Introduction
This post is on how to create a windows service that is self installing using c# and the managed installation features that comes with .net.The source code for this example can be found here: GitHub
Step1 - Creating the new project
First of all, we need to create a new project called SelfInstallingService. I am using visual studio 2010 (.net 4) for this project. This will be a standard console app. There are many tutorials on how to create a console app, so if you are unsure, I suggest you google it :)Step2 - Adding the references to the project.
You will need to add the following references to your project:- System.ServiceProcess
- System.Configuration.Install
Step3 - Creating the service
- Open the Program class and extend the class by inheriting from the ServiceBase class.
- Add a public static string to hold the current service name
- Create a new constructor in the Program class, and put the code you want to run there i.e. code that normally would go into the main method
You code will look as follows:
4. Add the following methods to the class and resolve the namespaces for the new classes being used:
protected override void OnStart(string[] args)
{
//start any threads or http listeners etc
}
protected override void OnStop()
{
//stop any threads here and wait for them to be stopped.
}
protected override void Dispose(bool disposing)
{
//clean your resources if you have to
base.Dispose(disposing);
}
private static bool IsServiceInstalled()
{
return ServiceController.GetServices().Any(s => s.ServiceName == InstallServiceName);
}
private static void InstallService()
{
if ( IsServiceInstalled())
{
UninstallService();
}
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
}
private static void UninstallService()
{
ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
}
5) Update the main method in the class to have the following code:
static void Main(string[] args)
{
bool debugMode = false;
if (args.Length > 0)
{
for (int ii = 0; ii < args.Length; ii++)
{
switch (args[ii].ToUpper())
{
case "/NAME":
if (args.Length > ii + 1)
{
InstallServiceName = args[++ii];
}
break;
case "/I":
InstallService();
return;
case "/U":
UninstallService();
return;
case "/D":
debugMode = true;
break;
default:
break;
}
}
}
if (debugMode)
{
Program service = new Program();
service.OnStart(null);
Console.WriteLine("Service Started...");
Console.WriteLine("<press any key to exit...>");
Console.Read();
}
else
{
System.ServiceProcess.ServiceBase.Run(new Program());
}
}
You can see that the following command line arguments can be input:
- /NAME - sets the name of the service
- /I - Installs the service
-/U - Uninstalls the service
-/D - Runs the service in debug mode i.e. a Console Application
Step4 - Creating the installed
1) Add a new class called CustomServiceInstaller and inherit from the Installer.2) Add a class attribute "RunInstaller" which takes a boolean value. Set this to value to True.
3) Resolve any namespace issues in the class.
You code will look as follows:
[RunInstaller(true)]
public class CustomServiceInstaller : Installer
{
}
4) In the same class, create a constructor that creates the new process info and service:
private ServiceProcessInstaller process;
private ServiceInstaller service;
public CustomServiceInstaller()
{
process = new ServiceProcessInstaller();
process.Account = ServiceAccount.LocalSystem;
service = new ServiceInstaller();
service.ServiceName = Program.InstallServiceName;
Installers.Add(process);
Installers.Add(service);
}
Step5 - Your done!
Your service is now complete. To run your program as debug, you can add the /D to your debug commands in the project settings, or you can set "debugMode" to true.Below is an example of the command lines you can use to install and uninstall the service:
Install a service with the default name:
SelfInstallingService.exe /IUninstall service with the default name:
SelfInstallingService.exe /UInstall a service with custom service name:
SelfInstallingService.exe /NAME SelfIntallingServiceCustom /IUninstall service with custom name:
SelfInstallingService.exe /NAME SelfIntallingServiceCustom /U
Good post although no need to do a where then any in you IsServiceInstalled method. Just return ServiceController.GetServices().Any(s => s.ServiceName == InstallServiceName);
ReplyDeleteThanks : ) Good suggestion. I have updated it.
DeletePerfect! Thanks
ReplyDeleteThanks a lot, that was a big help.
ReplyDeleteWhat about calling service.OnStop() in debugMode, or is this a bad idea?
[...]
Console.Read();
service.OnStop();
[...]
If you wanted to add the following:
ReplyDeletethis.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
... where would you do it in your code?
ManagedInstallerClass.InstallHelper(new string[] { Assembly.GetExecutingAssembly().Location });
ReplyDeleteis giving error
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Configuration.Install.dll
Additional information: The installation failed, and the rollback has been performed.
please suggest
Try using Admin rights
DeleteI tried this. It Shows that install has completed but I don't see any service with specified name in Local Services. Any idea?
ReplyDelete