Reinstalling and Moving Windows Services using bat file

Utilizing this bat file really makes moving windows services and re-installing them in a new location a fairly easy and quick task. I had an instance where I needed to move a currently running windows service to a new folder in a directory. I found that an easy way to do this was to just uninstall and reinstall the service itself. For this I used a .bat file that includes a couple commands. First, we have to stop the running service.

net stop "Adam's Windows Service"

The next command is using InstallUtil.exe to uninstall the current service. This is the full line for uninstalling.

c:\windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe -u "D:\Adams\AdamsWindowsService.exe"

As you can see, the ‘-u’ signifies uninstall.  Now that we have the service uninstalled we want to reinstall it using the new directory location.  This line looks almost exactly the same as above, however, there is no ‘-u’.  Have a look at the following to install.

c:\windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe "D:\AdamsNewDirectory\AdamsWindowsService.exe"

My service is now running from a new directory at D:\AdamsNewDriectory. The last thing to do is to restart the service.  This is almost the exact same as the first line except it includes a start.

net start "Adam's Windows Service"

Now that we have an AdamsServiceMove.bat (naming doesn’t matter) we can easily modify it for any service to and from any location as well.  Have a look at the full file below.

net stop "Adam's Windows Service" 
c:\windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe -u "D:\Adams\AdamsWindowsService.exe"
echo.
echo Please verify uninstallation ...
pause

c:\windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe "D:\AdamsNewDirectory\AdamsWindowsService.exe"

echo.
echo Starting Adam’s Windows Service...
pause

net start "Adam's Windows Service"

pause


Error 1053 The service did not respond to the start or control request in a timely fashion.

We had an issue arise lately where one of our servers got rebooted and the windows services on that box did not restart after the reboot like they should.  In the event logs, we were getting the following error.

Error 1053: The service did not respond to the start or control request in a timely fashion.

So after doing some research, it looked like we were doing too much in the Main() method and/or the constructor. In other words, all our processing was not finishing prior to timing out.  Now, we can start the services just fine after the box has booted.  So the issue is most likely while the box is being booted, its resources are too thin that even with the service set to Automatic (Delayed Start) that it’s just not finishing what it needs too.

So I dove into windows services a bit to figure out where we could move the bulk of our processing for initialization.  I came up with two solutions. First I recreated the problem so that I knew that’s what the real problem is. Take a look at the following.

using System.ServiceProcess;
using System.Threading;

namespace AdamsService
{
    public partial class Service1 : ServiceBase
    {
        //Called By Main Method.
        public Service1()
        {
            InitializeComponent();
        }

        //Runs First
        private static void Main()
        {
            ServiceBase[] ServicesToRun = new ServiceBase[] { new Service1() };

            Thread.Sleep(31000); //Simulates processing time leading to a time out.

            Run(ServicesToRun);
        }

        //Runs after main
        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
    }
}

This first example shows that the majority of the processing is happening in the Main() method.  As well, if you were to move the Thread.Sleep(31000) to the constructor Service1() you will get the same results.  If you build, deploy, and try to start this service locally you will receive a message like follows when you try to start the service.

Error 1053 Windows Service Fails To Start In Timely Fashion

Error 1053 Windows Service Fails To Start In Timely Fashion

So how do we fix it?  Let’s take a look at two solutions that seem to handle the extra processing time.  The first one, I basically moved the processing to the OnStart method.  This is run through the call in the Main method Run(ServicesToRun).  Moving the processing to OnStart allowed me to successfully start and run the service.

using System.ServiceProcess;
using System.Threading;

namespace AdamsService
{
    public partial class Service1 : ServiceBase
    {
        //Called By Main Method.
        public Service1()
        {
            InitializeComponent();
        }

        //Runs First
        private static void Main()
        {
            ServiceBase[] ServicesToRun = new ServiceBase[] { new Service1() };

            Run(ServicesToRun);
        }

        //Runs after main
        protected override void OnStart(string[] args)
        {
            Thread.Sleep(31000); //Simulates processing time leading to a time out.
        }

        protected override void OnStop()
        {
        }
    }
}

The second solution that seemed to work and seemed to be a common solution among others is to spin off a new thread from the Main() method.  This allows for almost instantaneously starting of the service and then the processing continues in the background.  Take a look at the following.

using System.ServiceProcess;
using System.Threading;

namespace AdamsService
{
    public partial class Service1 : ServiceBase
    {
        //Called By Main Method.
        public Service1()
        {
            InitializeComponent();
        }

        //Runs First
        private static void Main()
        {
            ServiceBase[] ServicesToRun = new ServiceBase[] { new Service1() };

            Thread worker = new Thread(DoProcessing);
            worker.IsBackground = false;
            worker.Start();

            Run(ServicesToRun);
        }

        private static void DoProcessing()
        {
            Thread.Sleep(31000);
        }

        //Runs after main
        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
    }
}

Both seem to work equally as well from the testing that I did.  I would be interested in others opinion if you have run into similar issues.