Virtual Developer Workshop: Containerized Development with Docker
Windows services have a few basic properties: They can be configured to run under a specific user. They can have parent or child services; a parent service is a service that your service is dependant on and a child service is a service that depends on your service. This comes into play when you start/stop services. For a clean start, you need to make sure the parent services of your service are started.
For a clean stop, make sure the child services of your service are stopped.
Now, start with the code: To control services in VB.Net, you need to import the service process namespace; therefore, your first line is:
First, just try to start a service without checking for any dependenciers on parent services.
Dim objWinServ As New ServiceController objWinServ.ServiceName = sServiceName objWinServ.MachineName = MachineName StartService(objWinServ) Private Sub StartService(ByVal Service As ServiceController) If Service.Status = ServiceControllerStatus.Stopped Then Try Service.Start() Service.WaitForStatus(ServiceControllerStatus.Running, _ System.TimeSpan.FromSeconds(20)) Catch ex As TimeoutException Status = "Could not Start " & Service.DisplayName & _ " - TimeOut expired" Catch e As Exception Status = "Could not Start " & Service.DisplayName & _ " - " & e.Message End Try End If End Sub
The code is fairly straightforward:
- Create a new service controller object called objWinServ.
- Assign the servcie name and machine name (because you're calling it remotely).
- Supply the objWinServ object to your start service routine.
- The routine first checks the status of the service to see if it is stopped. You can further check to see whether it's paused, running, and so forth.
- Then, it tries to start the service. I've put in a max wait of 20 seconds for the service to start. If it does not, it throws an timeout exception. I've put in a general exception clause as well.
Now, to make the code more robust, two things you may want to check for are:
- Parent Services that need to start before your service
- Whether the service actually exists on the server.
To check for parent services that need to be started, you use this recursive sub:
Private Sub CheckForParentServices _ (ByVal Service As ServiceController) Dim objParentService As ServiceController For Each objParentService In Service.ServicesDependedOn CheckForParentServices(objParentService) Next Call StartService(Service) End Sub
Pass objWinServ to the sub and let it do its magic!
To check whether or not the servcie exists, use this function that will return a boolean value depending on whether or not the service exists:
Public Function CheckforService(ByVal ServerName As String, _ ByVal ServiceName As String) As Boolean Dim Exist As Boolean = False Dim objWinServ As New ServiceController Dim ServiceStatus As ServiceControllerStatus objWinServ.ServiceName = ServiceName objWinServ.MachineName = ServerName Try ServiceStatus = objWinServ.Status Exist = True Catch ex As Exception Finally objWinServ = Nothing End Try Return Exist End Function
Now, look into stopping the service. First, the basic function:
Private Sub StopService(ByVal Service As ServiceController) Dim status As String If Service.Status = ServiceControllerStatus.Running Then Try Service.Stop() Service.WaitForStatus(ServiceControllerStatus.Stopped, _ System.TimeSpan.FromSeconds(20)) Catch ex As TimeoutException status = "Could not Stop " & Service.DisplayName & _ "Service - TimeOut expired" Catch e As Exception status = "Could not Stop " & Service.DisplayName & _ "Service - " & e.Message End Try End If End Sub
Pass objWinServ, with the same kind of exception handling and wait times.
You can use the same function as earlier to check whether or not the service exists, but when it comes to stopping a service, you need to check if the service has any dependant child servcies that also need to be stopped. The Sub for that is:
Private Sub CheckForChildServices(ByVal Service As ServiceController, _ ByVal NextService As String) Dim objChildService As ServiceController For Each objChildService In Service.DependentServices CheckForChildServices(objChildService, NextService) Next If NextService = "Stop" Then Call StopService(Service) Else Call ContinueService(Service) End If End Sub
I've added a second attribute, 'NextService', for this sub. This is to make the child service check sub more reusable. You need to check for child services if you want to change the status to continue as well. So, you add an attribute that can take values of stop or continue.
Here's the sub for continue service. You can write a similar one for pause as well.
Private Sub ContinueService(ByVal Service As ServiceController) Dim status As String If Service.Status = ServiceControllerStatus.Paused Then Try Service.Continue() Service.WaitForStatus(ServiceControllerStatus.Running, _ System.TimeSpan.FromSeconds(20)) Catch ex As TimeoutException status = "Could not change status from Paused To _ Continue for " & Service.DisplayName " _ " - TimeOut expired" Catch e As Exception status = "Could not change status from Paused To _ Continue for " & Service.DisplayName & " - " _ & e.Message End Try End If If Service.Status = ServiceControllerStatus.Stopped Then Call StopService(Service) End If End Sub