ProblemYou want to view the services that a particular service depends on (i.e., antecedent services) and services that are dependent on that service. This is helpful to know when you want to stop a service and determine the impact it would have on other services. SolutionUsing a graphical user interface
Using a command-line interfaceThe following command displays the services that depend on a service: > sc enumdepend <ServiceName> The following command displays the services that a service depends on: > sc qc <ServiceName> Using downloadable softwareYou can also use the Sysinternals psservice command to enumerate dependencies: > psservice <ServiceName> depend Using VBScript' This code lists the antecedent and dependent services for a service ' ------ SCRIPT CONFIGURATION ------ strService = "<ServiceName>" ' e.g. TapiSrv strComputer = "<HostName>" ' e.g. wks01 (use . for local system) ' ------ END CONFIGURATION --------- set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") set colServices = objWMI.ExecQuery("Associators of " _ & "{Win32_Service.Name='" & strService & "'} Where " _ & "AssocClass=Win32_DependentService Role=Antecedent" ) WScript.Echo "Antecedent services for " & strService & ":" for each objService in colServices Wscript.Echo vbTab & objService.DisplayName next WScript.Echo set colServices = objWMI.ExecQuery("Associators of " _ & "{Win32_Service.Name='" & strService & "'} Where " _ & "AssocClass=Win32_DependentService Role=Dependent" ) WScript.Echo "Dependent services for " & strService & ":" for each objService in colServices Wscript.Echo vbTab & objService.DisplayName next A practical use of enumerating dependencies is for programmatically restarting a service. You could just call the Stop and Start methods on a service as we showed in Recipe 10.16, but if you tried to restart a service that had a dependency, the restart would fail. An alternative is to write a bit of code that can handle restarting services, regardless of dependencies. Here is that code: ' This code restarts a service by first stopping all ' dependent services before stopping the target service. ' Then the target service is started and all dependent ' services are started. Option Explicit ' ------ SCRIPT CONFIGURATION ------ Dim strComputer : strComputer = "." ' e.g. fs-rtp01 Dim strSvcName : strSvcName = "Alerter" ' e.g. dnscache ' ------ END CONFIGURATION --------- Dim objWMI : set objWMI = GetObject("winmgmts:\\" & strComputer & _ "\root\cimv2") Dim objService: set objService = objWMI.Get("Win32_Service.Name='" & _ strSvcName & "'") WScript.Echo "Restarting " & objService.Name & "..." RecursiveServiceStop objService RecursiveServiceStart objService WScript.Echo "Successfully restarted service" Function RecursiveServiceStop ( objSvc ) Dim colServices : set colServices = objWMI.ExecQuery("Associators of " _ & "{Win32_Service.Name='" & objSvc.Name & "'} Where " _ & "AssocClass=Win32_DependentService Role=Antecedent" ) Dim objS for each objS in colServices RecursiveServiceStop objS next Dim intRC : intRC = objSvc.StopService if intRC > 0 then WScript.Echo " Error stopping service: " & objSvc.Name WScript.Quit else WScript.Echo " Successfully stopped service: " & objSvc.Name end if End Function Function RecursiveServiceStart ( objSvc ) Dim intRC : intRC = objSvc.StartService if intRC > 0 then WScript.Echo " Error starting service: " & objSvc.Name WScript.Quit else WScript.Echo " Successfully started service: " & objSvc.Name end if Dim colServices : set colServices = objWMI.ExecQuery("Associators of " _ & "{Win32_Service.Name='" & objSvc.Name & "'} Where " _ & "AssocClass=Win32_DependentService Role=Antecedent" ) Dim objS for each objS in colServices RecursiveServiceStart objS next End Function DiscussionService dependencies play a role in how you can stop a service. For example, if ServiceA depends on ServiceB, then ServiceB must be running before ServiceA can start. Similarly, ServiceB cannot be stopped until ServiceA is stopped due to the dependency. A good practical example of this is the Logical Disk Manager Administrative service. It depends on the Logical Disk Manager service. It wouldn't make a lot of sense for the administrative service to be running, while the underlying disk manager service (the thing it manages) was not. Service dependences are configured in each service's Registry entry. In the case of the Logical Disk Manager Administrative service, you can find its Registry entry in the following key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\dmadmin If you open Registry Editor (regedit.exe) and look at that key, you'll see a DependOnService value. The data for this REG_MULTI_SZ value is a list of the services it depends on. One of them is dmserver, which corresponds to the Logical Disk Manager service. You may also see a DependOnGroup value under a service's Registry key. This is similar to DependOnService except that DependOnGroup corresponds to a group of services. For more on service groups, check out Recipe 10.22. Using VBScriptTo enumerate dependencies, we need to use something called a WMI associator. The Associators of clause in a WQL query is similar to a table join in a relational database. It allows you to relate two different types of classes. For services, WMI supports a class called Win32_DependentService, which defines the service dependencies for a given service. The first query finds all of the antecedent services (those that depend on the target service). Here is the query: "Associators of {Win32_Service.Name='" & strService & "'} Where " _ "AssocClass=Win32_DependentService Role=Antecedent" The Associators of clause tells WMI we are going to associate or join another class to the one specified within the curly braces. We set Win32_Service.Name equal to the target service. The Where clause then has two parts. The first sets the associated class, which in this case is Win32_DependentService; the second part (Role=Antecedent) limits the dependent services that are returned to just antecedent services, or ones that depend on the target service. The only difference with the second query is that the query sets Role=Dependent, which returns all of the dependent services of the target service. In the service restart example, you have to stop all services that are dependent on the service and then stop the service itself. Then to start the service, you have to start the service followed by all dependent services. And that is exactly what that code does. It makes use of a couple of recursive functions that walk through all of the dependent services. |