ADSI exposes two interfaces for managing services in Windows NT: IADsService and IADsServiceOperations. The IADsService interface is responsible for manipulating the configuration of an installed service, whereas the IADsServiceOperations interface provides the bulk of service- related administration. In this section, we will take a look at the IADsService interface. Using this interface, you can do the following:
Enumerate services installed on a given machine.
Query and set service dependencies.
Modify the naming, paths, and behavior of installed services.
Query the status of a specific service.
As shown in Figure 6.1, to display a list of services installed on a computer, you can simply open the Services applet in control panel. If you want to generate a list of all services on a given machine, you can easily do so by binding to the computer object, then narrow the result set to just services using the IADsContainer Filter property.
By combining this enumeration process with the properties and methods of the IADsService and IADsServiceOperations interfaces, you can quickly write administrative applications without ever referring to a native API reference manual.
Consider the following Visual Basic code to generate a list of services on a given machine:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain &"/"& ComputerName & ",computer") Computer.Filter = Array("service") Dim Service As IADsService For Each Service In Computer Debug.Print Service.Name Next
Tip
While in the For Next loop, you can easily call upon any of the IADsService properties or methods to display or modify information related to each individual service .
If you know the programmatic name (usually the name of the service executable) of the service you want to manipulate, you can bind directly to the service for further manipulation and queries. Consider the following Visual Basic code to form the basis of these queries and manipulations:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService)
Windows NT allows the developer/administrator the ability to define dependent services for any given service. If you attempt to stop a service upon which other services are dependent, these services will also be stopped .
To discover which services are dependent on a specific service, use the following Visual Basic code:
On Error Resume Next Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) If IsArray(Service.Dependencies) = True Then Dim Entry As Variant For Each Entry In Service.Dependencies Debug.Print Entry Next Else Debug.Print Service.Dependencies End If
Upon examining the code, you can see that the list of dependencies is returned as an array, which you can then enumerate to display each individual dependent service.
Tip
For an example of the behavior of the dependency property, look at the relationship between the IISADMIN and W3SVC services. On machines with IIS installed, if you stop the IIS ADMIN service, this action will force a dialog box querying whether you also want to stop the www publishing service (W3SVC). When you examine the Dependencies property of the W3SVC service, you see that the IISADMIN service is defined as a dependency of the W3SVC .
If a new service was just installed and you want to define a new dependency for the service, this is easily performed using ADSI. Consider the following Visual Basic code to perform this action:
On Error Resume Next Dim Computer As IADsComputer Dim Service As IADsService Dim NewElement() As Variant Dim i As Long Dim EmptyArray As Integer Dim DependencyAlreadyExists As Integer Dim ComputerDomain As String Dim TargetComputer As String Dim TargetService As String Dim NewDependency As String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " TargetComputer = " Target_Computer_Name " NewDependency = "mssqlserver" Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & TargetComputer & ",computer") Set Service = Computer.GetObject("service", TargetService) If IsArray(Service.Dependencies) = True Then Dim Entry As Variant For Each Entry In Service.Dependencies i = UBound(NewElement) + 1 ReDim Preserve NewElement(i) NewElement(i) = Entry If Entry = "" Then EmptyArray = 1 If Entry = NewDependency Then DependencyAlreadyExists = 1 Next If EmptyArray = 1 Then Service.Dependencies = Array(NewDependency) Service.SetInfo Else If DependencyAlreadyExists <> 1 Then i = UBound(NewElement) + 1 ReDim Preserve NewElement(i) NewElement(i) = NewDependency Service.Dependencies = NewElement Service.SetInfo End If End If Else If Service.Dependencies <> NewDependency Then Service.Dependencies = Array(Service.Dependencies, NewDependency) Service.SetInfo End If End If
When manipulating an installed service, you may notice that the name used for binding the service does not match the name displayed in the Services dialog box. Windows NT allows the administrator/developer to define an additional entry for each service to reference the service in a more friendly way. The service name property is a short name used for programmatic identification of the service that matches the name of the service executable. The service display name property is a string that can be defined to enable a more friendly method for manipulating services using GUI tools.
To query the display name for a given service, use the following Visual Basic code:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Debug.Print Service.DisplayName
If you cannot easily derive the name of a service from its display name, use the following Visual Basic code to return the name in the Visual Basic IDE's Immediate window:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim StringToFind as String ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " StringToFind = " Display_Name_To_Find " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Computer.Filter = Array("service") Dim Service As IADsServiceFor Each Service In Computer If InStr(Service.DisplayName, StringToFind) <> 0 Then Debug.Print Service.Name; " = "; Service.DisplayName End If Next
After finding the service name from the display name, simply use the service name to manipulate the bound service.
Tip
If you convert the preceding code segment to a function, you can pass the results into other service-related functions in a single line of Visual Basic code, as follows :
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String Dim ServiceDisplayName as String ServiceDisplayName = "Display_Name_of_Service" ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " TargetService = GetServiceName(ServiceDisplayName, ComputerDomain, ComputerName) Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Debug.Print Service.HostComputer Public Function GetServiceName(DisplayName as String, ComputerDomain as String, ComputerName as String) as String Dim Computer as IADsComputer Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ", computer") Computer.Filter = Array("service") Dim Service As IADsService For Each Service In Computer If InStr(Service.DisplayName, DisplayName) <> 0 Then GetServiceName = Service.Name End If Next End Function
If you no longer wish to retain the name previously assigned to a service, you can easily redefine it by setting a new value to the DisplayName property. Use the following Visual Basic code to perform this task:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String Dim NewDisplayName as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " NewDisplayName = " New_Service_Display_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Service.DisplayName = NewDisplayName Service.SetInfo
The HostComputer property defines the ADsPath of the machine hosting the executable used for the service. In most cases, the HostComputer property will match the ADsPath of the currently bound computer object.
Use the following Visual Basic code to return the value of the HostComputer property:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Debug.Print Service.HostComputer
Note
This property cannot be set programmatically using ADSI .
Windows NT services are executables that can be run outside of the current user 's context. Each service maintains the path of its executable, which can be queried by examining the Path property of a bound service object. Use the following Visual Basic code to determine the path to the executable for the bound service:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Debug.Print Service.Path
If you wish to move the executable associated with a service, you can potentially do so without reinstalling the service. Simply manipulate the Path property of the IADsService interface after moving the executable image within the file system.
Note
Although you can modify the Path property while the service is running, the change will not take affect until the service has been cycled .
Use the following Visual Basic code to change the path to the service executable:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String Dim NewServicePath as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " NewServicePath = " New_Path_To_Executable " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Service.Path = NewServicePath Service.SetInfo
All services run under the context of another user account. Whether the account is explicitly defined or is simply the LocalSystem account, it is run outside the current user context. This allows services to run even when a user is not logged in and to perform privileged operations when a non- privileged account is currently logged in.
Using the GUI, if you click the Startup button in the Service dialog box, you can determine the user account associated with any given service (see Figure 6.2). Using the IADsService interface, you can also perform this same query programmatically.
To query which account is being used for a service, simply display the value of the ServiceAccountName property of the IADsService interface. The following Visual Basic code demonstrates this process:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Debug.Print Service.ServiceAccountName
Tip
Combined with an enumeration function, you can find the service account used with all services on a given machine .
Note
This property cannot be set programmatically using ADSI .
You can query the method used to start the service by examining the ServiceStart property of the IADsService interface. Five constants can be used, but only the last three in Table 6.1 are commonly used in Windows NT.
Constant | Value |
---|---|
ADS_SERVICE_BOOT_START | |
ADS_SERVICE_SYSTEM_START | 1 |
ADS_SERVICE_AUTO_START | 2 |
ADS_SERVICE_DEMAND_START | 3 |
ADS_SERVICE_DISABLED | 4 |
Warning
If you attempt to set a value that is not in the table (such as 5), an error will occur .
Using the preceding table and the following Visual Basic code, you can determine the startup type for any service running on a system:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) Select Case Service.StartType Case 0 Debug.Print "BOOT" Case 1 Debug.Print "SYSTEM" Case 2 Debug.Print "AUTOMATIC" Case 3 Debug.Print "MANUAL" Case 4 Debug.Print "DISABLED" End Select
You can also set a new startup type for a service by passing in a new integer value representing one of the startup type constants. Use the following Visual Basic code to programmatically manipulate the startup method for a service:
Dim Computer as IADsComputer Dim ComputerName as String Dim ComputerDomain as String Dim Service As IADsService Dim TargetService as String TargetService = " Target_Service_Name " ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Computer = GetObject("WinNT://" & ComputerDomain & "/" & ComputerName & ",computer") Set Service = Computer.GetObject("service", TargetService) 'Use 4 to disable the service, 3 for Manual startup or 2 to AutoStart the service Service.StartType = 4 Service.SetInfo
Note
Notice that you are assigning the StartType property to an integer as represented in the table of constants shown in the earlier section "Querying Service Start Type Using Visual Basic" .
Top |