Windows Service never call OnStop() method when shutdown - c#

I have simplest possible windows service.
I need service to run under Local System account.
If I start/stop service from SCM, everything works fine, my log text file has both Start and Stop events, and also both Start and Stop events are shown automatically in the event viewer.
But when I restart or shutdown my PC (tried with Win 7 and Win 10), OnStop() method is never called, if service runs as Local System account. If I change account to Network Service or any other Local/Domain account, OnStop() method is called before restart/shutdown of the PC.
Windows service code:
using System.IO;
using System.ServiceProcess;
namespace SimplestService
{
class MyService : ServiceBase
{
private string path = "<pathtologfile>\\MyServiceLog.txt";
public MyService()
{
this.ServiceName = "MyService";
this.CanShutdown = true;
}
protected override void OnStart(string[] args)
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine("MyService Started.");
}
}
protected override void OnStop()
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine("MyService Stopped.");
}
}
protected override void OnShutdown()
{
OnStop();
}
}
}
and Main Entry:
using System.ServiceProcess;
namespace SimplestService
{
class Program
{
static void Main(string[] args)
{
ServiceBase.Run(new MyService());
}
}
}
For simplicity I've used SC utility to create service, even though I tried with Installer, even setup project (msi), but with same results.
sc create MyService binPath= "<pathtoexe>\SimplestService.exe"
type= own start= auto DisplayName= Myservice

Microsoft Windows has added an option called Fast Startup which does not actually shutdown the computer.
As noted in the Fast Startup setting description, Restart isn't affected. This is why the Restart triggers OnShutdown and Shutdown does not.
Turning off Fast Startup will trigger OnShutdown for both Restart and Shutdown.

From what I researched, the OnShutdown method is called when the OS is shutdown, but there is there is a strict time limit, but i believe the local system services are terminated even before this time limit so that OS shutdown time is fast. This might explain why domain account are shutdown slower. Windows has introduced a PreShutdown event to handle this.
Try the link below, it has more information on this
https://www.atomia.com/2011/11/16/how-to-process-the-preshutdown-event-in-a-managed-windows-service/

Related

C# Running console application as windows service - The service didn't respond error

I'm trying to run some console app as windows service, I followed this question, and I made a few changes to make it fit to my app.
My main code looks like that:
public static class Program
{
public class Service : ServiceBase
{
public Service(string serviceName)
{
this.ServiceName = serviceName;
}
protected override void OnStart(string[] args)
{
Program.Start(args);
}
protected override void OnStop()
{
Program.Stop(this.ServiceName);
}
}
#endregion
static void Main(string[] args)
{
if (!Environment.UserInteractive)
// running as service
using (var service = new Service("TestService"))
ServiceBase.Run(service);
else
{
// running as console app
Start(args);
}
}
private static void Start(string[] args)
{
while(true)
{
//DO SOMTHING
}
}
private static void Stop(string serviceName)
{
//Writing to log that 'serviceName' stopped
}
}
I tried to run the following console app as a service, by using the following steps:
1) Use the command: sc create ServiceTestName123 binPath= "PATH TO THE EXE FILE IN THE PROJECT DEBUG FOLDER".
2) Use the command: sc start ServiceTestName123 "parameter1".
And I got an error:
"StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion"
I read about the error in the internet and found out that I can try to solve this problem by running the start function with another thread, so I updated the OnStart function to the following function:
protected override void OnStart(string[] args)
{
Thread t = new Thread(() => Program.Start(args));
t.Start();
}
After trying to re-create the service (delete the old one and create the service again with the new OnStart function) and re-run it I got the same error.
By the way, when I ran this code as console app it worked properly.
Could someone please explaing me what am I doing wrong?
Thanks a lot.
I tried your exact steps and it worked for me. I will highlight a few key points that I came across
OnStart should definitely return in a timely fashion. i.e. the work should happen in a separate process/thread. I used your code for thread and it worked fine for me.
Make sure the executable is on a local drive which can be accessed from your "Local System" account without any permission issues.
Make sure when you create the service, you provide the absolute path and not relative path.
Make sure the sc create ... command responds back with [SC] CreateService SUCCESS
Check the service was created in the service control panel
Make sure you can start it from the service control panel before attempting it from command line
Also, open task manager or process explorer to make sure the service executable is running or not (irrespective of what status is returned by service control panel or scm start)
For debugging, I logged the information into a local temp file - again watch out for permissions issues with Local System account.
If for whatever reasons you have to delete the service, make sure that it indeed disappeared from the service control panel
To debug what's going on, you can attach the debugger at the very beggining of your program start up.
This way, you can check what your program is doing.
You can also check in the Windows ever viewer, the error that windows is throwing.
Put this line at the start trace of your program:
System.Diagnostics.Debugger.Launch()

Very simple C# Windows Service - Malwarebytes quarantines it. Am I doing something questionable?

I am trying to learn about writing Windows Services, and I'm using C# to do it. I found a tutorial on Microsoft's site here:
https://msdn.microsoft.com/en-us/library/zt39148a%28v=vs.110%29.aspx
It shows you how to build a simple Windows Service that logs some messages to the Event Log. I more or less followed the instructions, and everything worked fine. But it instructs you to use Designers and mysterious drag-and-drop components, and to rely upon a bunch of IDE-autogenerated code. So, for the purposes of trying to actually understand what I was doing, I tried to make a (basically) equivalent Windows Service just from raw classes that I manually typed in, rather than from Designers and such.
It compiled fine, and installutil.exe successfully installed it as a service. But when I try to start the service, I get the following error:
Windows could not start the Bob Manual Service Display Name service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion.
Eventually I figured out that Malwarebytes (my antivirus program) is quarantining my project's compiled exe whenever I try to start the service. It says it's infected with "Backdoor.Bot". I have tried both debug and release builds, and it quarantines both.
Obviously I could just whitelist the exe or temporarily disable Malwarebytes or whatever, but I am completely new to this Windows Service stuff, and I am concerned that I am perhaps unknowingly doing something flagrantly wrong or dangerous in my code.
I am attaching my code, which is intended to be based on the Microsoft sample code but very simple - three small classes, a Main, a System.ServiceProcess.ServiceBase, and a System.Configuration.Install.Installer.
Is there any reason why Malwarebytes should be quarantining this?
One thing that I imagine might look questionable is that I'm setting the account to ServiceAccount.LocalSystem, which that Microsoft tutorial says has "broad permissions" and so "might increase your risk of attacks from malicious software", but:
(1) That's what it is in Microsoft's sample code (and as I understand it, it's required for the EventLog stuff);
(2) I actually accidentally had it as LocalService at first, and the same error was happening.
namespace Project1
{
using System.ServiceProcess;
static class BobMain
{
static void Main()
{
ServiceBase[] ServicesToRun = { new BobManualService() };
ServiceBase.Run(ServicesToRun);
}
}
}
namespace Project1
{
using System.Diagnostics;
using System.ServiceProcess;
public class BobManualService : ServiceBase
{
private EventLog eventLog;
public BobManualService()
{
this.eventLog = new EventLog();
if (!EventLog.SourceExists("BobSource"))
{
EventLog.CreateEventSource("BobSource", "BobLog");
}
this.eventLog.WriteEntry("Super duper constructor!");
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
}
}
namespace Project1
{
using System.ComponentModel;
using System.Configuration.Install;
using System.ServiceProcess;
[RunInstaller(true)]
public class BobInstaller : Installer
{
private ServiceProcessInstaller serviceProcessInstaller;
private ServiceInstaller serviceInstaller;
public BobInstaller()
{
this.serviceProcessInstaller = new ServiceProcessInstaller();
this.serviceInstaller = new ServiceInstaller();
this.serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
this.serviceProcessInstaller.Password = null;
this.serviceProcessInstaller.Username = null;
this.serviceProcessInstaller.AfterInstall +=
this.serviceProcessInstaller_AfterInstall;
this.serviceInstaller.Description =
"Bob Manual Service Description";
this.serviceInstaller.DisplayName =
"Bob Manual Service Display Name";
this.serviceInstaller.ServiceName = "BobManualService";
this.serviceInstaller.StartType = ServiceStartMode.Automatic;
this.Installers.AddRange(new Installer[]
{
this.serviceProcessInstaller,
this.serviceInstaller
});
}
private void serviceProcessInstaller_AfterInstall(
object sender,
InstallEventArgs e)
{
}
}
}
Looking at your code, in the OnStart(string[] args) method, there is no process being started that runs on a separate thread for a prolonged time. So your service starts and exists immediately. Please take a closer look at "To define what occurs when the service starts" in the tutorial that you've referenced.
Basically just add the code that sets up the timer to the OnStart(string[] args) method and your service should stay alive.

Service Application will not stay running

I am building an application monitoring service to write to the event log so I can get an general Idea how often the computer is being used. I can install the service and when I try to run it I get this error:
"The Application Monitor service on local computer started and then stopped. Some services stop automatically if they have no work to do, for example, the performance logs and alerts service."
I've tried a while loop, mouse activity, and etc... but it keeps ending. any ideas on what I can do?
public ApplicationMonitor()
{
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists("Activity Usage"))
{
System.Diagnostics.EventLog.CreateEventSource("Activity Usage", "Computer Log");
}
eventLog1.Source = "Activity Usage";
eventLog1.Log = "Computer Log";
}
protected override void OnStart(string[] args)
{
eventLog1.WriteEntry("In OnStart");
}
protected override void OnStop()
{
eventLog1.WriteEntry("In onStop.");
}
protected override void OnContinue()
{
eventLog1.WriteEntry("In OnContinue.");
}
Because there is no active thread.
You need to start your thread that does the polling in the "OnStart" method of your service. Otherwise when the OnStart method completes, there is no active thread in the application and the .Net CLR will close the app.
Even if the thread is simply doing a thread sleep every 30 seconds, it must be alive in order for the app to stay open.

c# windows service with filewatcher

First time posting long time reader.
I built a working filewatcher inside of a windows forms application functioning 100% properly before moving it to a windows Service and am now recieving two seperate issues. This file watcher reads a flatfile for line updates(lastwrite), deletes/recreates file(streamwriter), and finally parses through a strongly typed data set and then uploads to an SQL server.
(This is my first Windows Service)
Questions:
1. Does the double event trigger in filewatcher effect the service differently then a forms application?
2. Does anyone have an answer about why the thread will break if the class I am calling has no issue?
3. Are there any known issues with Windows Authentication through a windows service?
4. Does anyone have any strong debug methods for windows services?
Here is my code from the windows Service, thanks in advance and my apologies if there is a silly mistake in the code, again first time making a windows service.
FileMonitor m_FileMonitor;
public WindowsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
Thread myThread = new Thread(DoTheWork);
myThread.Start();
}
catch
{
}
}
void DoTheWork()
{
m_FileMonitor = new FileMonitor(Properties.Settings.Default.PathToFileToWatch, Properties.Settings.Default.PathToErrorLog);
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
For debugging, make sure your project type is Windows Application, and then use this:
[DllImport("kernel32")]
static extern bool AllocConsole();
private static void Main(string[] args)
{
var service = new MyService();
var controller = ServiceController.GetServices().FirstOrDefault(c => c.ServiceName == service.ServiceName);
if (null != controller && controller.Status == ServiceControllerStatus.StartPending)
{
ServiceBase.Run(service);
}
else
{
if (AllocConsole())
{
service.OnStart(args);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
service.OnStop();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
If the code is running because the Windows Service was started, it will run as a Windows Service. Otherwise it will allocate a console, run the service, then wait for a key press before exiting the service. You could build on this for testing pause and continue.
For debugging:
You have to use the ServiceBase.Run method in Main() to execute as a windows service, but you can make a switch in the main method to run the same application as a normal console application (e.g. --standalone). I'm using this on all my services to make them easy to debug.
Regarding the other problems:
I'm not completely sure which problems you encounter and what you mean by "class break" and "double event trigger".
Windows services run under a special service account, which might or might not have permissions to watch the directory you are interested in. You can change the service account or give it permission for the directory if you need to.
Links:
Here is a link to a codeproject article who seems to have implemented a file watcher windows service. Maybe it helps:
http://www.codeproject.com/Articles/18521/How-to-implement-a-simple-filewatcher-Windows-serv

Create a combo command line / Windows service app

What's the best way in C# to set up a utility app that can be run from the command line and produce some output (or write to a file), but that could be run as a Windows service as well to do its job in the background (e.g. monitoring a directory, or whatever).
I would like to write the code once and be able to either call it interactively from PowerShell or some other CLI, but at the same time also find a way to install the same EXE file as a Windows service and have it run unattended.
Can I do this? And if so: how can I do this?
Yes you can.
One way to do it would be to use a command line param, say "/console", to tell the console version apart from the run as a service version:
create a Windows Console App and then
in the Program.cs, more precisely in the Main function you can test for the presence of the "/console" param
if the "/console" is there, start the program normally
if the param is not there, invoke your Service class from a ServiceBase
// Class that represents the Service version of your app
public class serviceSample : ServiceBase
{
protected override void OnStart(string[] args)
{
// Run the service version here
// NOTE: If you're task is long running as is with most
// services you should be invoking it on Worker Thread
// !!! don't take too long in this function !!!
base.OnStart(args);
}
protected override void OnStop()
{
// stop service code goes here
base.OnStop();
}
}
...
Then in Program.cs:
static class Program
{
// The main entry point for the application.
static void Main(string[] args)
{
ServiceBase[] ServicesToRun;
if ((args.Length > 0) && (args[0] == "/console"))
{
// Run the console version here
}
else
{
ServicesToRun = new ServiceBase[] { new serviceSample () };
ServiceBase.Run(ServicesToRun);
}
}
}
The best way to accomplish this from a design standpoint is to implement all your functionality in a library project and build separate wrapper projects around it to execute the way you want (ie a windows service, a command line program, an asp.net web service, a wcf service etc.)
Yes it can be done.
Your startup class must extend ServiceBase.
You could use your static void Main(string[] args) startup method to parse a command line switch to run in console mode.
Something like:
static void Main(string[] args)
{
if ( args == "blah")
{
MyService();
}
else
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new MyService() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
A Windows Service is quite different from a normal Windows program; you're better off not trying to do two things at once.
Have you considered making it a scheduled task instead?
windows service vs scheduled task

Categories