Service about to stop - detect the cause - windows

In a Windows service, my Service Control Handler receives a SERVICE_CONTROL_STOP command. I would like to determine the reason for this command; specifically, I need to know whether the STOP was requested because a depended-upon service ("master") is stopping or because of any other reason. The reason is, if my service stopped because the user requested a stop or because Windows is shutting down or any other similar reason, I don't need to do anything, but if my service is stopping because master is stopping, I need to make sure I restart my service when master restarts.
Unfortunately, I don't really see any source of this information - RegisterServiceCtrlHandlerEx will let me provide a handler which can get some details behind the control event, but there doesn't seem to be a notification that I can use. But maybe there's some other way, e.g. getting the info through the Session Manager or something.

In a Windows service, my Service Control Handler receives a SERVICE_CONTROL_STOP command. I would like to determine the reason for this command
Sorry, but the SCM does not provide that information to services.
specifically, I need to know whether the STOP was requested because a depended-upon service ("master") is stopping or because of any other reason.
There is no way for your service to determine that.
The reason is, if my service stopped because the user requested a stop or because Windows is shutting down or any other similar reason, I don't need to do anything
Detecting Windows shutting down is easy - your service can request to receive SERVICE_CONTROL_PRESHUTDOWN and SERVICE_CONTROL_SHUTDOWN events. For any other stop reason, it will only receive SERVICE_CONTROL_STOP with no explanation as to why.
if my service is stopping because master is stopping, I need to make sure I restart my service when master restarts.
There are two possible ways to handle that:
run a separate process that monitors the status of "master", either by regularly polling QueryServiceStatus() or by using NotifyServiceStatusChange(), and have it start your service when it detects "master" stop and restart.
if "master" logs events in the system log via an ETW provider, you can use ChangeServiceConfig2(SERVICE_CONFIG_TRIGGER_INFO) to register a trigger action that starts your service when a particular event is logged.
Unfortunately, I don't really see any source of this information - RegisterServiceCtrlHandlerEx will let me provide a handler which can get some details behind the control event, but there doesn't seem to be a notification that I can use.
Correct, because there isn't one.

Related

Does windows stop services gracefully or kills them when an error (memory overflow, etc) occurs?

Firstly sorry for my poor english. I don't really know how to formulate the question, but I can explain you my intentions so it may help you to understand me better.
Im developing tool that notifies you when a windows service goes down.
The exact logic that I follow is:
When a service goes down gracefully logs an event that you can see in windows event viewer. I've created a sheduled task that will be triggered when the service is stopped according to windows event log (Thanks to a XML filter).
This task triggers a powershell script that sends a request to a telegram bot that will notify me when the service dies.
This process works perfectly when I manually stop the service (From service.msc or Powershell's Stop-Service). The objective is to have a realtime track of the service, and in this case works correctly.
The problem comes here: I cannot force the service to crash in order to see if it logs information in windows event viewer.
My questions are:
If an error occurs will windows shut the service down gracefully (like when using Stop-Service) or will it kill the process without registering any log info (like when using taskkill /f)?
Any other suggestions? Is there another way to track a windows service in real time and trigger a script without a loop that runs every certain time.
Hope y'all understand me :)
If a service crashes, you should still see an error message in the event log under Windows Logs > System. The Source will be "Service Control Manager" and Event ID should be either 7031 or 7032 or 7034.
So you can add a filter for these and have your PowerShell script run on these kinds of events as well.

How to tell a Windows service to restart or reload its configuration?

I have a GUI application that is used to configure a windows service and I want to start, stop or restart this service from thing GUI application.
One of the problems is that this service can run in two modes: windows service or manually from command line (so you have a console).
Now, I am looking for a way to communicate this, a way that would work in both cases.
It may be helpfull to specify that the service process already has and even handler that is dealing with:
CTRL_C_EVENT
CTRL_CLOSE_EVENT
CTRL_BREAK_EVENT
CTRL_LOGOFF_EVENT
CTRL_SHUTDOWN_EVENT
It would be quite easy to extend the handler if I knew what event will be triggered by the service restart option. Still, I should be able to trigger the same event from my GUI application so I will be able to tell the "server" to restart itself even if it is running in background.
The best is would be if I could do this without having to detect in which mode the server application is running.
There are Service Trigger Events that your service can listen for, and then your GUI can send an event. In particular, you want to register for an SERVICE_TRIGGER_TYPE_CUSTOM trigger, which causes your service to listen for an ETW event; your GUI code would then write the ETW event to trigger the event.
There is no service restart action. All you would do is stop the service normally, then start the service normally afterwards. That is all the SCM restart does internally, it is just exposed as a single operation in the SCM UI instead of as two separate options.

How to list Windows Services from within a Service

sc query state= all works as expected from the command line.
From within another Service, sc query state= all doesn't print anything to that sub-process' stdout (captured by the parent, of course).
Is there a permission/privilege that the Service needs in order to list/start/stop the other servies?
A little background: I am making a service that periodically restarts some misbehaving services.
Well, for one don't do that, at least not in a blocking manner. In order for your own service to respond to the SCM (Service Control Manager) in order to return its status, the service has to be able to execute its dispatcher code. This means that if you call this program and wait for it to exit you'll wait indefinitely. One way to mitigate this would be to put this into a separate thread so it's not blocking your dispatching and your service will continue to talk to the SCM.
Alternatively (and probably better) you could use the EnumServicesStatusEx function to talk to the SCM and inquire about the statuses of other services yourself. The function itself doesn't mention anything about being blocking, so you'd have to figure out yourself whether it is and then use a thread again to prevent your service from stopping to talk to the SCM.
One last note: if those misbehaving services are yours, you should more likely fix the respective code. I've had a share of legacy code and had one misbehaving service which got its own helper application as "fault action" (can be configured in service configuration as SERVICE_CONFIG_FAILURE_ACTIONS) that would go about and restart the service whenever it crashed. Once I took that code over, figured out the cause and fixed it, the service was stable again and that application isn't really needed anymore.

How to make sure that my service is always up and running

I have created a service in Windows and set enteries in Registry so that the service automatically starts on log on.
Now the problem is that in Task manager->Services field, my service's status is Running for only 2-3 minutes after log-on.
After this time my service status turns to Stopped, and it never again switches to running.
It also doesnot do its designated work.
I want to know that what changes in Registry or the Properties of the service can be made to make sure that service is always running.
Chances are that you are getting an unhandled exception which is shutting down the process.
You need to add logging to your windows service - something that will write all exceptions to the event log is a fairly common thing to do.
This will allow you to see why the service is stopping. At this point you will hopefully have enough information to fix the coding error.
I want to know that what changes in Registry or the Properties of the service can be made to make sure that service is always running.
Well, assuming the issue is with your service, there is no configuration that will help.

Windows Services Recovery not restarting service

I configure the recovery for Windows services to restart with a one minute delay after failures. But I have never gotten it to actually restart the service (even with the most blatant errors).
I do get a message in the EventViewer:
The description for Event ID ( 1 ) in Source ( MyApp.exe ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: Access violation at address 00429874 in module 'MyApp.exe'. Write of address 00456704.
Is there something else I have to do? Is there something in my code (I use Delphi) which needs to be set to enable this?
Service Recovery is intended to handle the case where a service crashes - so if you go to taskmgr and right click "end process" on your service process, the recovery logic should kick in. I don't believe that the service recovery logic kicks in if your service exits gracefully (even if it exits with an error).
Also the eventvwr message indicates that your application called the ReportEvent API specifying event ID 1. But you haven't registered your event messages with the event viewer so it can't convert event ID 1 into a meaningful text string.
Service Recovery only works for unexpected exit like (exit(-1)) call.
For all the way we use to stop the service in usual way will not works for recovery.
If you want to stop service and still wants recovery to work, call exit(-1) and you will see error message as "service stopped with unexpected error" , and then your service will restart as recovery setting is.
The Service Control Manager will attempt to restart your service if you've set it up to be restarted by the SCM. This is detailed here in the documentation for the SERVICE_FAILURE_ACTIONS structure.
A service is considered failed when it
terminates without reporting a status of SERVICE_STOPPED to the
service controller.
This can be fine tuned by setting the SERVICE_FAILURE_ACTIONS_FLAG structure's fFailureActionsOnNonCrashFailures flag, see here). You can set this setting from the Services applet by checking the "Enable actions for stops with errors" checkbox on the recovery tab.
If this member is TRUE and the service has configured failure actions, the failure actions are queued if the service process terminates without reporting a status of SERVICE_STOPPED or if it enters the SERVICE_STOPPED state but the dwWin32ExitCode member of the SERVICE_STATUS structure is not ERROR_SUCCESS (0).
If this member is FALSE and the service has configured failure actions, the failure actions are queued only if the service terminates without reporting a status of SERVICE_STOPPED.
So, depending on how you have structured your service, how you have configured your failure actions AND what you do when you have your 'fatal error' it may be enough to call ExitProcess() or exit() and return a non zero value. However, it's probably safest to ensure that your service exits without the code that's dealing with the SCM telling the SCM that your service has reached the SERVICE_STOPPED state. This ensures that your failure actions ALWAYS happen...
If you 'kill' service from task manager - forgot for recovery logic. In background task manager 'kills' process by 'stop service'. and as yuo can guess - this is not service failure. This forced me to kill it really with Visual Studio. In task manager right click on service process. Select debug.
In Visual studio select Debug-> Terminate All.
And now you have simulated service fail. In this case recovery logic works fine.

Resources