All these times I have worked on nearly 10-12 windows services so far which serves the business purpose of handling background jobs and invoke the necessary business logic on a particular time.
I was looking for more deployment options, so that i can deliver the Windows Service to the target system, without making the user to follow so many instructions(command line instructions, installer etc).
I am familar with the two most common options for deploying Windows Service on targetted systems
1. Having a batch script using the “InstallUtil.exe” that comes with the .NET Framework to get the Service assembly installed on the deployment system. or calling through command line using the same “InstallUtil.exe”, in both cases we need to mention the path to “InstallUtil.exe” in our Target .NET Framework version folder.
For Example:
[code lang=”vb”]
C:WINDOWSMicrosoft.NETFrameworkv2.0.50727InstallUtil.exe "c:MyServicesMyService1MyService1.exe
[/code]
The above command is using the .NET Framework 2.0 specifically. If i keep "
C:WINDOWSMicrosoft.NETFrameworkv2.0.50727InstallUtil.exe" on a "ServiceInstaller.bat", i am telling the script run InstallUtil.exe from
C:WINDOWSMicrosoft.NETFrameworkv2.0.50727.
How about if the deployment system has the windows installed in "D:", then user has to change this manually to "D:" drive in the "ServiceInstaller.bat".
This is the batch files I used to install(ServiceInstall.bat).
[code lang=”vb”]
@ECHO OFF
REM The following directory is for .NET 2.0
set DOTNETFX2=%SystemRoot%Microsoft.NETFrameworkv2.0.50727
set PATH=%PATH%;%DOTNETFX2%
echo Installing MyService…
echo —————————————————
InstallUtil /i MyService.exe
echo —————————————————
echo Done.
pause
[/code]
To Uninstall(UnintallService.bat) I used the following:
[code lang=”vb”]
@ECHO OFF
REM The following directory is for .NET 2.0
set DOTNETFX2=%SystemRoot%Microsoft.NETFrameworkv2.0.50727
set PATH=%PATH%;%DOTNETFX2%
echo Uninstalling MyService…
echo —————————————————
InstallUtil /u MyService.exe
echo —————————————————
echo Done
[/code]
Installutil.exe is not compatible across Frameworks. You can’t install a 1.1 assembly with the 2.0 installutil, so you have to make sure you are using the right target framework all the time, when you run “batch” script.
2. an MSI Installer which auto install the windows service on the deployment system.
This is really a nice way for deploying windows service.
Now i found a way we can install the service assembly directly from the code, with out the need to run the “InstallUtil.exe” through command line or batch script.
InstallHelper, in the System.Configuration.Install.ManagedInstallerClass class. By using this method, we can install or uninstall the service from the command line, with out need to manually call the installutil.exe from the .NET Framework folder to install the service.
The idea is to install the service directly from the command line like give below
For installing : MyService.exe /i
For Uninstalling : MyService.exe /u
This is the code I created, with help of “System.Reflection” and “System.Configuration.Install” I augmented the Main() function in the service class to look like this:
[code lang=”c-sharp”]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.ServiceProcess;
using System.Text;
namespace SchedulerSvc
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (args.Length > 0)
{
// InstallHelper, in the System.Configuration.Install.ManagedInstallerClass class.
// By using this method, I can install or uninstall the service from the command line.
//Installs the Service
if (args[0].Trim().
ToLower()== "/i")
{
System.Configuration.Install.ManagedInstallerClass.InstallHelper(new string[] { "/i",Assembly.GetExecutingAssembly().Location });
}
//Uninstalls the service
else if (args[0].Trim().
ToLower() == "/u")
{
System.Configuration.Install.ManagedInstallerClass.InstallHelper(new string[] { "/u", Assembly.GetExecutingAssembly().Location });
}
}
else
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
//ServiceBase[] ServicesToRun;
//ServicesToRun = new ServiceBase[]
//{
// new Service1()
//};
//ServiceBase.Run(ServicesToRun);
}
}
}
[/code]
For installing : MyService.exe /i
Installing the following line of code is called, which utilizing the System.Configuration.Install.ManagedInstallerClass.InstallHelper class which handles the functionalities of the “InstallUtil.exe”.
[code lang=”c-sharp”]
System.Configuration.Install.ManagedInstallerClass.InstallHelper(new string[] { "/i",Assembly.GetExecutingAssembly().Location });
[/code]
For Unistalling : MyService.exe /u
Similarly for uninstalling “u” is passed as command line argument while calling the executable.
[code lang=”c-sharp”]
System.Configuration.Install.ManagedInstallerClass.InstallHelper(new string[] { "/u",Assembly.GetExecutingAssembly().Location });
[/code]
This is pretty cool right. If our Service Executable itself is having the “Self-Installing” capability.
This is just some alternative, Not completely matured.
I have to test the scenarios like situation when the service is already installed and i am trying to install it again using “/i”.
I will update more later.
That’s all for now. Happy Learning!!!!
Discover more from Cloud Distilled ~ Nithin Mohan
Subscribe to get the latest posts sent to your email.
Hi , Nithin Good Article.
Great article 🙂
I have a couple of questions…
What does the code in the else do (on the check for args having a length)?
When I use the code and from the command line type myService.exe /i I get an error:
“Cannot start service from the command line or a debugger. A Windows Service must first be installed (using installutil.exe) and then started with the ServerExplorer, Windows Services Administrative tool or the NET START command.”
Any ideas what I have done wrong??
Thanks,
Jen
Ignore that, I worked it out (I was stupid and had two mains!)
Now I am being prompted for a username and password when installing the service, I have the property of the process installer to be localService, any other ideas how I can stop the prompt?
Thanks
Jen
Solved! (I should wait a while before I comment…) it was setting my processInstaller.Account to be System/ServiceProcess.ServiceAccount.LocalService within the ProjectInstaller constructor (in case anyone else is reading this!)