5
Controlling Services
and Drivers
So far, we have discussed various methods for provoking scripts into running unattended and have shown how these scripts can be used to carry out more or less any maintenance task that you can throw at them. In order to perform these tasks, the scripts use mainly a combination of system utilities and registry hacks. When writing such scripts, the easiest way to find out which registry entries might need adjusting in order to achieve a desired effect is often simply to browse through the registry hives manually; failing that, there are always reference books!* In short, it is seldom difficult to find what you are looking for. There is one aspect of maintenance and configuration, however, that can be looked after admirably by scripting but whose configuration can be rather more troublesome, namely, controlling services and drivers.
There are hosts of reasons why you might want to control services and drivers through scripts. A few possibilities are listed here:
- To start or stop services that should be working only at certain times of day, or in certain circumstances, such as when a workstation is temporarily acting as a print spooler.
- To silence nonfatal startup errors that occur as a result of driver failures when it is not necessarily appropriate actually to remove the driver. An obvious example is a driver for a removable tape drive that complains whenever the drive is not connected.
- To control third-party utilities, such as virus protection systems and schedulers, many of which run as services.
Starting and stopping services is easy: simply use the net.exe utility as described later on. The complications can arise when trying to configure aspects of service or driver behavior, such as startup type or error control. These may be stored as mere registry entries, but finding them—while perfectly possible—is not always easy and is certainly not quick. Furthermore, workstations may well be running drivers and services for NT provided by third-party vendors rather than by Microsoft itself; reference material that describes service parameters in a very generic way will not necessarily be able to answer the questions you need to ask. Often, setting up successful control of drivers and services through scripts requires a little detective work; this chapter suggests how this might be approached.
The chapter opens with a brief discussion of net.exe; we show how it can be used to perform simple service control. The remainder of the text is devoted to the demonstration of techniques that can be used to develop scripts that control drivers and services and to discover some hidden configuration parameters that might at first sight seem nonconfigurable. First, we describe the use of utilities that can locate registry entries associated with service configuration parameters that are set trivially through the GUI; then we describe the potential role of Event Viewer in the isolation and diagnosis of service and driver problems. Finally, we present a short script whose writing would be near impossible without either registry monitoring or a very in-depth knowledge of the workings of NT.
Controlling Services with net.exe
This is not the first time that the utility net.exe has been mentioned; nor will it be the last. The command-line utility, which comes as part of the standard NT installation and has existed since the days of MS-DOS and LanManager, contains a whole host of functions that can manipulate various aspects of Microsoft's networking protocols. A discussion of the rich feature set that the utility provides would be out of place and unnecessary here. Instead, we will concentrate only on one subset of its features, namely, its service-controlling capabilities.
There are three incantations of net.exe that are concerned with controlling services. All are invoked directly from the command line; they are listed here:
- net start with no extra parameters displays a list of currently running services.
- net start servicename starts the specified service. Only services registered with the Service Control Manager (i.e., Win32-based services—see Chapter 2, Running a Script Without User Intervention) can be started from the command line in this way; driver services cannot. A user attempting to start a service must have administrative privileges.
- net stop servicename stops the specified service. The rules governing use of this command are identical to those governing net start. In other words, the service specified by servicename must be registered with the Service Control Manager, and the user must have administrative privileges.
By way of example, we will present the commands that would be required to start and stop the spooler service, thereby enabling and disabling print spooling on a workstation.
C:\>net start spooler
The Spooler service is starting.
The Spooler service was started successfully.
C:\>net stop spooler
The Spooler service was stopped successfully.
Attempting to start a service that does not exist or is not installed properly produces an error:
C:\>net start toaster The service name is invalid. More help is available by typing NET HELPMSG 2185. C:\>net helpmsg 2185 The service name is invalid. EXPLANATION You tried to start a service that is not configured on this system. ACTION Check the spelling of the service name or check the configuration information for the service using the Services option from Server Manager.
Likewise, attempting to stop a nonexistent service produces an error. You will note, however, that in this case, net.exe does not suggest the use of net helpmsg 1060. The reason for this is that the one-line error returned is not a summary but the full text associated with Windows Error 1060.
C:\>net stop toaster System error 1060 has occurred. The specified service does not exist as an installed service.
Attempting to stop a service that does exist but is not currently running also gives an error:
C:\>net stop spooler The Spooler service is not started. More help is available by typing NET HELPMSG 3521. C:\>net helpmsg 3521 The *** service is not started.
In this case, the invocation of net helpmsg 3521 serves no useful purpose at all. There is no rational explanation why the output of net stop suggests its use.
Finally, attempting to start a service that is already running displays an error:
C:\>net start spooler The requested service has already been started. More help is available by typing NET HELPMSG 2182. C:\>net helpmsg 2182 The requested service has already been started. EXPLANATION You tried to start a service that is already running. ACTION To display a list of active services, type: NET START
This message is actually useful!
Incorporating the functionality offered by net.exe into a script is easily accomplished. In its simplest form, a script to toggle the status of the spooler service would need only one line of code:
‘net $ARGV[0] spooler‘;
This program would start or stop the spooler service, depending on the first command-line parameter passed when the script is invoked. Of course, this line of code provides no feedback. A script will normally need to know whether its invocation of net.exe was successful. To achieve this, it could do one of two things:
- Use the Perl system() function to call net.exe rather than the ‘ syntax. Whereas the latter returns the output of the called command as it would normally be presented to standard output, the former returns the exit code from the called process. Universally, an exit code of 0 means that the command executed successfully.
$answer = system("net $ARGV[0] spooler"); if($answer == 0) { print "Net command successful\n"; } else{print "Net command failed\n";}
The only problem with this solution is that any command executed with system() displays its output as if called manually from the command line.
- The other solution, if the first one isn't appropriate, is to use the ‘ syntax (which suppresses normal output display) and to read the value of $?. Immediately after the call to net.exe, this variable will contain a return code of 0 if the operation was successful. The following script uses this syntax:
‘net $ARGV[0] spooler‘; if($? == 0) { print "Net command successful\n"; } else {print "Net command failed\n";}
As can be seen, if the extent of your wish to control services through scripting is limited to starting and stopping nondriver services, then net.exe provides a simple and efficient interface for doing this.* If you require more extensive control or need to alter the state of services that are not registered with the Service Control Manager, more sophisticated and, alas, more cumbersome methods are required. The remainder of this chapter is devoted to these.
Services Versus Drivers
We have been bandying about the terms service and driver as though the two were interchangeable. It is now time to pause for a few moments to explain what the differences and similarities are. As discussed in Chapter 2, services come in two varieties: Win32-based services and device drivers. When discussing automatic logins, we were concerned with only the former category. However, configuration scripts may well be concerned with both sorts, so drivers deserve a short mention. The fundamental difference between a driver and a service is the interface to which each must adhere: whereas a Win32-based service must behave in the way that the Service Control Manager expects, a driver service must behave in accordance with the Windows NT device driver protocols, which are documented in the Driver Development Kit. Drivers do not communicate with the Service Control Manager.
Unless you intend to write your own drivers, it is safe to push programming issues aside and declare that the fundamental difference between a driver and a service is that a driver tends to be at a lower level, providing interfaces primarily to hardware and a few base services, whereas Win32-based services tend to be of a higher level. Another difference of import to a system administrator is that, whereas Win32-based services appear in the Service Control Panel, drivers appear in the Drivers Control Panel.
For the system administrator, drivers and services are similar in terms of generic configurability: the Devices Control Panel permits the same setting of startup type, hardware profile, and so on. Configuration changes made here are stored under the same services key of the registry; crucially, this means that the techniques we are about to describe in the next section of this chapter apply equally for both species.
Finding Registry Entries
So now to the main thrust of this chapter, namely, that it's all very well declaring that services and drivers can be manipulated with a few registry entries, but how do you go about finding out what to change? Well, if you're not lucky enough to have the hive, key, value name, and value slapped in your face like a wet kipper, then you need to do some registry monitoring. Essentially, this involves tracking changes to registry values dynamically, as those changes are made. Three utilities that we have used while developing our configuration techniques are NT's own auditing features, sysdiff.exe (a utility that comes on the NT Server and NT Workstation CDs (\Support\DepTools\platform) as well as in the NT Resource Kit) and a freeware utility Regmon.exe. Whichever tool is used, the principle is the same: if there is an aspect of the workstation that is ordinarily configurable through the Control Panel (or another GUI interface), monitor the registry, make the change through the GUI, and see which (if any) registry values were written. We'll start by showing how to implement this technique using NT's built-in auditing tools, and then move on to sysdiff and Regmon.
Monitoring the Registry Through Auditing
You are probably aware that NT has a mechanism for auditing resources and documenting certain actions by writing information about them (often quite cryptically) into the event log. Depending on the resource type, NT presents a number of event types that a system administrator can choose to audit, thereby determining whether an action has been carried out successfully. The registry is one of the many objects that can be audited.
So how to go about setting up auditing? Short of programming, you can set registry auditing only through the registry editor Regedt32. However, before anything you might do here has any effect, an auditing policy for the machine has to be established.* To turn on auditing, launch User Manager and select from the main menu Policy → Auditing. The event type you want to set for auditing is File and Object Access.
Having set your audit policy, there are three steps you need to take to successfully set up an audit:
- Establish which key to audit: Launch Regedt32 and traverse through one of the five hives it offers you. Once you have found the desired key, highlight it.
- Set “who” is to be audited: From Regedt32's main menu, select Security → Auditing. From the resulting window, add one or more users or groups to the audit list. In our case we simply select the group “everyone” as we are interested in what actions occur, not in the name under which these actions happened.
- Set the actions to be audited: Now check from the list of actions any action you want to audit. For each action this involves selecting checkboxes for auditing success, failure, or both. Out of the nine actions listed as potential audit targets, there are five of relevance to us here. The five relevant audit targets are described in Table 5-1.
Access Types | Actions That Generate Audit Events |
Query value | Attempting to read a registry key value |
Set value | Attempting to modify a registry key value |
Create subkey | Attempting to create a new subkey under the registry key that is being audited |
Enumerate subkey | Attempting to read the subkeys of the registry key under audit |
Delete | Attempting to delete the selected registry key |
Don't set the key to audit to the root key of any of the hives, especially not HKEY_LOCAL_MACHINE or HKEY_USERS, and at the same time check Audit Permissions on Existing Subkeys. Your machine will start a seemingly endless cycle of writing audit events to the event log, of no use to man or beast. The only time you might ever want to audit everything is to prove to a skeptic that the OS really does access the registry rather a lot as it goes about its business.
The following example—although slightly contrived—gives an idea as to how we can use the auditing mechanism so far described.
Question: There is an option that can be set via the Control Panel that specifies how long a machine should wait for user input before proceeding with the default hardware profile selection at boot time. Where in the registry is this value set?
We know how to do this via the Control Panel, and are prepared to bet that the setting is stored somewhere in the registry. This makes this task an ideal candidate for auditing, so here goes: The first question we need to ask is what key should we set auditing on? The trouble is, we don't know; finding out is the whole purpose of this exercise. Well, true, but this method needs some help. We have to make an intelligent guess as to what type of key we are interested in, or the log will be flooded with entries, and even if it doesn't actually fill up, plowing through them looking for the thing in which we are interested would take an eternity! We know the key we are looking for is related to the machine (rather than, say, a user); we know, therefore, that it must be set in HKEY_LOCAL_MACHINE. We also know that it is not related to the machine in any physical way, so we can guess that it's the SYSTEM rather than the HARDWARE key we are interested in. Under the SYSTEM key we note the existence of a CurrentControlSet key. This seems a likely point to stop and try our luck.
We now carry out the second and third steps of the research process. For step 3 we choose to audit the action Set Value for “success.” We also audit the Create Key action for “success” just in case a key and associated value don't already exist. At this stage it is worth launching the Event Viewer application and clearing out the security log. This will make things a bit clearer when we come to trawl through the logs later.
Now open the System Properties dialog box (right-click on My Computer and select Properties from the menu) and select the Hardware Profiles tab. Change the wait time to, say, 20 seconds, apply the new setting and switch back to the Event Viewer. Refresh the log and you should get a dozen or so new entries in the event log.
The final stage of this example is to look through the events and see if any give us the clue we are looking for. On inspection we find the following in one of the event records:
Object Open: Object Server: Security Object Type: Key Object Name: \REGISTRY\Machine\System\ControlSet001\Control\IDConfigDB New Handle ID: 0 Operation ID: {0,452293} Process ID: 2166013440 Primary User Name: Administrator Primary Domain: ANNAPURNA Primary Logon ID: (0x0,0x6011D) Client User Name: - Client Domain: - Client Logon ID: - Accesses Set key value Privileges -
We are interested, in this case, only in the Object Name and the Accesses fields. The Accesses entry Set key value informs us that the key named under Object has had its value modified. As you can see, the Object Name displays:
\REGISTRY\Machine\System\ControlSet001\Control\IDConfigDB
The first part of this string, \REGISTRY, informs us that it is the registry that has been altered as opposed to a file or other object. The \Machine reference tells us that the key in question is in the hive HKEY_LOCAL_MACHINE; the remainder of the string points us to the actual key, in this case IDConfigDB. Unfortunately, it doesn't tell us which value under this key has been changed. So now we need to do a bit of manual labor. Using Regedt32, we will traverse our way to the key IDConfigDB and note down the value names and associated values of this key. Now we change the wait time again and refresh the screen to see what has changed. It may be the case that the value name itself gives us a pretty good idea of its intended purpose. The screen shot in Figure 5-1 shows the final answer to our question. As you can see, the last value under the key IDConfigDB is UserWaitInterval which, I think you'll agree, is a pretty big clue. The value is 0x14, which, when presented as a decimal number, translates to 20 seconds.
The process may have been long winded, but the information that it has yielded would allow the writing of a script that altered the wait time for choosing a hardware profile at boot time.
Salient points about this registry monitoring method are:
- It comes as a standard with NT.
- It is crude and requires some intuitive guessing.
- It doesn't directly give you the value you are looking for.
- It takes time.
Monitoring Changes with sysdiff.exe
A rather more satisfactory method of achieving the same effect without the hassle and manual labor associated with registry auditing is to use sysdiff.exe. This utility, which comes as part of the NT Server Resource Kit, was designed to facilitate the automation of application distribution. The basic idea is that you run the utility once to create a “snapshot” of your workstation and then install the application you intend to distribute. Running sysdiff for a second time (with different parameters) will generate a so-called difference file, containing all the changes that the installation made to the system. A third incantation of the utility, with this difference file as a parameter, will duplicate those changes on any workstation on which it is run. The rationale is that software has to be installed manually only once; future installations are taken care of by sysdiff.
sysdiff is a fairly sophisticated utility offering a variety of command-line options that allow applications to be distributed from a package residing on a network drive. It can even generalize any user-specific settings that an installation routine makes to the system. Here, we are concerned with only one feature of the utility, which is actually a by-product of its main functionality: although run from the command line, it has a GUI in which it displays all the changes that are recorded. The utility may be designed to record changes made by an application installation program (registry changes and file modification and addition), but there is no reason why we cannot use it to monitor registry activity caused by altering NT configuration with GUI components of the operating system.
In order to use sysdiff to monitor the registry, carry out the following steps:
- Install the sysdiff executable (sysdiff.exe) and its configuration file (sysdiff.inf) on your workstation.
- Type sysdiff /snap filename. This will create a snapshot of the current workstation status and store this snapshot under filename.*
- Perform the operation that you wish to monitor in exactly the same way as when using NT auditing to track changes.
- Type sysdiff /diff oldfile newfile. This will create a binary difference file under the filename newfile, containing all the changes that have been carried out since oldfile was created. In terms of the current pursuit we are not too interested in newfile; its use would be in duplicating the changes elsewhere. Instead, we are interested in the GUI output of sysdiff: one of the panes it displays will list any registry entries that were altered. This is exactly the information we need.
Despite our claim that newfile itself is useless as far as we are concerned here, it should be pointed out that it does have one use. Typing sysdiff /dump newfile sanefile at the command prompt will produce a text file listing all the changes recorded in newfile, in plain English.*
Salient features of the sysdiff approach to registry monitoring include:
- The utility is a standard part of the NT Server Resource Kit.
- The utility provides exact information, obviating the need for manual digging.
- The utility compares differences with snapshots rather than tracking in the true sense, so it must be run twice to produce any results and relies on an up-to-date snapshot file.
- If a situation requires altering the sysdiff.inf configuration file, this can be a time-consuming pain.
Monitoring the Registry with Regmon.exe
Regmon.exe provides a quick and easy way to locate keys and values that control the behavior of drivers and services. It is a freeware utility that consists of two parts, a device driver and a GUI interface. Its purpose is to monitor and log all registry activity; unlike sysdiff, this utility tracks registry changes in real time. You can download a copy from Systems Internals at http://www.sysinternals.com. The best way to demonstrate its usefulness is to provide an example of its operation.
Question: Which registry values need to be modified in order to prevent the TCP/IP service from starting at the next (and subsequent) reboots?
- Launch the Regmon GUI program (Regmon.exe). The first thing to do is to turn off capturing, or else you will end up with a much larger data set than is really necessary or useful.† To do this, select Events → Capture Events from the main menu. It toggles on or off as you click on it. As we are only interested in finding which keys are changed, we can restrict Regmon's monitoring remit so that it captures only successful writes. To do this, select Events → Filter from the main menu and make sure that only Log Writes and Log Success are checked from the checkboxes presented. Leaving the Log Read checkbox on will produce a much larger data set than is necessary here and will slow the system down immeasurably.
- Open the Control Panel (Start → Settings → Control Panel) followed by the Devices applet. Now scroll down the list box until you find the TCP/IP entry and highlight it. Now, before going any further, switch back to Regmon and turn capturing back on, ready to log any changes that might occur. As we are looking to disable the service, return to the Devices Control Panel and select the button marked Startup; from the list of radio buttons presented, select the Disable option.
- Return to Regmon. In its main window, you will see a list of keys and value names that have been modified or created by the act of setting the Disable option for the TCP/IP service. Actually in this case we get just two entries, as shown in Figure 5-2.
We will ignore the first column of the display; it simply displays numbers as they are assigned to all logged activities. The second column shows the name of the process that made the changes. The third indicates the type of action that was carried out on the key or value. The fourth column details the actual key and value to which a modification attempt (in this case) was made; the fifth, whether it has been successful. The final column, strangely labeled as Other, shows what the value has been set to.
It should be clear from this display that setting the Startup option of the TCP/IP service to Disable causes the value of HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Start to be set to 0x4. With a little experimentation using this technique, it is possible to deduce what hexadecimal values represent all of the startup states available for the TCP/IP service. They are detailed in Table 5-2.
State | Hex Representation |
Boot | 0x0 |
System | 0x1 |
Automatic | 0x2 |
Manual | 0x3 |
Disable | 0x4 |
As can be seen from the preceding example, Regmon is an invaluable tool for monitoring the registry in real time, a task that can greatly speed up the process of deducing what registry keys are involved in controlling services and drivers. Whereas auditing the registry with NT's built-in capability is a tedious business, and sysdiff can be rather unwieldy (as it was designed primarily to create software distribution packages), Regmon is lightweight, trivial to use, but extremely powerful.
Registry monitoring, in conjunction with GUI-based tools, provides a powerful technique for quickly discovering which registry entries are associated with aspects of driver and service behavior. In fact, the technique can be put to good use in any situation in which you need to find a registry entry associated with a configuration parameter that can be set trivially from a GUI or command-line operating system component. Salient points about this registry monitoring method follow:
- It does not require any manual digging to discover which registry keys are involved in the change you are trying to make.
- It is a freeware utility.
- It monitors the registry in real time.
- It is incredibly simple to use.
In the context of services and drivers, however, this technique is not always sufficient, as there are several aspects of configuration that cannot be set through GUI utilities at all. The resolution of driver conflicts and the like can often be achieved if you know what some of these “hidden” settings actually are. Although it does not provide answers directly, much insight into this can be gained by reading the logs of the Event Viewer. In the next section, we show you how to read these logs and use the information presented to deduce relationships between drivers and services, thereby revealing something of the hidden workings of these beasts.
Event Viewer and Beyond
Event Viewer is a utility that comes as part of the standard NT Workstation distribution. Its purpose, as can be guessed from the name, is to view and manage the event logs. There are three distinct event logs that can be read with Event Viewer, one for applications to report to, one dedicated to security logging, and one for the system; it is this last that we are interested in. An item in the event log contains the following fields: date, time, user, computer, event ID, source, type, category, and description. The date, time, and computer fields are self-explanatory, merely noting the date and time that an event was logged and the name of the computer that raised the event (information that is clearly of use only in a networked environment). User and category are not relevant to the present concerns, because a current user is not a valid concept at boot time. Category is also not relevant because it is used only by software that chooses to categorize the types of events that it logs: Windows NT services, on the whole, do not so choose. This leaves event ID, source, type, and description, which deserve a slightly fuller explanation:
- The event ID is a unique number that identifies—in fact, defines—the event. In most cases it will be the same as the index given to the error that the source raises internally. It may well be used by the source itself in some way in its own error-raising code. It can often also be cross-referenced against documentation when you are trying to identify a problem; Windows NT error numbers are for the most part documented in the Win32 API.
- The source is the name of the program that logged the event. In the present context, this field may contain either the name of the service that fails to start (if it has been programmed to write to the event log). More likely, if the service does not use the event log, if it doesn't exist, or if it does not respond to the start request, the Service Control Manager will log the error, and so it is this name that the source field will contain.
- There are five event types: information, warning, error, success audit, and failure audit. The first three of these tokens indicate the seriousness of the logged event; the final two concern only security audits and will not be discussed further here. An event classified at the information level might be something along the lines of notification that the event service has started. Whereas information-level events are normally seen only when examining the event logs, warnings and errors almost invariably announce themselves in the form of an onscreen dialog.
- The description field gives a string corresponding to the Event ID and sometimes further details in either text or binary format.
In order to make this all a little clearer, we will illustrate the sort of information provided by Event Viewer with the help of a real-world example. Imagine that two workstations on a network have been configured with an identical NetBIOS name. Normally, such a situation would occur either by accident or as an artifact of an automatic operating system installation, and clearly neither of the workstations in question would work properly on a network. For the present, let us assume that we are ignorant of this fact. We are simply presented with a workstation that is not allowing network access and that warns on bootup that a service or device has failed. In order to understand more fully what is going on, we turn to Event Viewer. For the purposes of this discussion, we will assume that we are dealing with Windows NT workstation with a typical network configuration. We will also ignore the date and time, and assume that the machine is called USED-TWICE. Here is a description of the errors we might find:
First, the Workstation service (source) raises an error (type) with Event ID 3870. This corresponds to the description “USED-TWICE is not a valid computer name.”
This is followed by three errors (type) raised by the Service Control Manager (source):
Event ID: 7001 Description: The Messenger service depends on the Workstation service which failed to start because of the following error: A duplicate name exists on the network. Event ID: 7023 Description: The Workstation service terminated with the following error: A duplicate name exists on the network. Event ID: 7001 Description: The Computer Browser service depends on the Workstation service which failed to start because of the following error: A duplicate name exists on the network.
You will notice that two of the errors share the same Event ID, although one refers to the failure of the Messenger Service to start, and the other refers to the computer browser. This is because, in both cases, the Service Control Manager, which has discretion as to which Event ID to assign, raises the event. Although the two entries in the log concern different services, both are under the jurisdiction of the Service Control Manager (Services.exe), and it chooses to assign the same Event ID. Presumably, it does this because the error in both cases is caused by the same problem, namely, that “a duplicate name exists on the network.”
In the preceding example, both the Browser Service and the Messenger Service failed to start because they “depended” on the Workstation Service. Dependency is not discovered on a “try it and see” basis; every time a new driver or service is installed, it registers all those other services and drivers upon which it depends. As you may have guessed, dependency is one of those aspects of service (or driver) configuration that is not configurable through the Control Panel but is stored in the registry. As should be apparent from the examples of the previous section, lurking within the key HKLM\SYSTEM\CurrentControlSet\Services is a series of keys, each of which refers to one service in the current control set.* Some of the keys and values to be found in this part of the registry have already been introduced, both earlier in this chapter and previously in Chapter 2, Running a Script Without User Intervention, and Chapter 3, Remote Script Management. As promised there, we now provide details of what a couple of the more usefully modifiable values are for.
Each service key contains a series of values that define the corresponding service's behavior—its startup parameters and so on. One of these—the one highlighted by the preceding examination of event logs—is DependOnService; this value, unsurprisingly, lists other services that must be running in order for the current service to start successfully. An examination of, say, the DependOnService value in NetBT key (the one that sets up NetBIOS over TCP/IP) will reveal that it depends on the TCP/IP service. This is hardly shocking news! Unfortunately, this claim is a slight oversimplification, because if you actually look at the NetBT key, you will see the following:
DependOnService 54 63 70 69 70 00 00
Believe it or not, this sequence of bytes actually corresponds to the ASCII values “TCPIP.” Why Microsoft chose to record the data in binary form, when the service names to which this value refers are stored as ASCII text, is quite beyond us; but ours is not to reason why.
While browsing this section of the registry, there is another often underconfigured value that can be very useful, namely ErrorControl. This binary value sets the severity level of start failure. By altering this value, it is possible to suppress errors and warnings emanating from services altogether or alternatively to insist that a service is so important that, if it fails to load, the operating system should halt. Table 5-3 enumerates the error control options that are available for all services and drivers. The errors related to duplicate NetBIOS names that we have seen in the preceding example are all at level 01. This explains why failure of the Workstation Service and its dependents to load caused an error dialog to appear on startup but did not actually prevent the operating system from loading successfully.
Value | Option |
00 | Continue loading OS and do not report. |
01 | Continue loading OS but report error. |
02 | Severe error—stop loading OS and revert to Last Known Good hardware profile (if it exists). |
03 | Critical error—as 02. |
One situation in which the manipulation of error control values can be extremely useful is when running a configuration script that makes use of automatic logins, such as is often used when deploying workstations for the first time. If a set of workstations has been created from a disk-image clone or from an NT unattended installation, every one of them will have the same NetBIOS name—it is no coincidence that this is the example we used earlier! You may have written a script that takes advantage of auto-logons to configure each workstation with its own identity (the next two chapters show you how to do just this), but the script will not work, as autologon will stall when the error dialog pops up. Judicious manipulation of error control values will solve the problem.
For this particular situation, when you wish to suppress all errors relating to network services, there are two more global approaches that can be adopted.
The first approach is surprisingly easy to implement:
- Open the registry key HKLM\SOFTWARE\Microsoft\Windows NT\Current-Version\Windows.
- Create a binary value (REG_DWORD) named NoPopupsOnBoot.
- Set its value to 0x1.
As the name of the value implies, the preceding procedure will suppress error dialogs that occur at boot time. Problem solved! Of course, to solve the problem this way attacks the symptoms, not the cause, and is therefore not to be condoned—it might not work in all situations. For example, if a service whose error control parameter causes a severe or critical error fails, NT will not even load. From the point of view of ensuring that a script that does not rely on network services is not hampered by their failure, the most satisfactory solution is to prevent the services from starting at all. This is the second approach to the problem.
The Hardware Profiles Control Panel provides a facility for switching off all networking components in one fell swoop. If you follow the next series of steps, you will see how to use this feature, in conjunction with registry monitoring, to deduce which registry values must be set in order to disable all network services. This information can be used to write a script that can prevent these services from causing any problems or displaying any errors at startup.
- Set Regmon running and then open the System Properties dialog box (right-click on My Computer and select Properties from the menu). Then select the Hardware Profiles tab. Here, if you select the Properties button followed by the Network tab, you will see a single checkbox entitled Network-disabled Hardware Profile. Exactly what we need! Select it and then the OK button.
- Return to the Regmon window. You will see an entry similar to the following: HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Current\System\ CurrentControlSet\Enum\ROOT\LEGACY_SMC1211\0000\CSConfigFlags.
- You will notice that the value is set to 0x1. This single key disables all networking for the currently selected hardware profile. On reboot you'll have no network connectivity and, even if duplicate NetBIOS names are used throughout the network, there will be no errors displayed. As you may have guessed, reinstating connectivity involves setting the value to 0x0.
How does this rather strange registry value disable network services? Actually it is quite simple. Any entries that appear under the SYSTEM\CurrentControlSet\HardwareProfiles subkey of HKEY_LOCAL_MACHINE detail special configuration information relevant only to specific hardware profiles. Rather than having a totally separate part of the registry for each hardware profile, Windows NT has been designed so that only exceptions to the norm have to be noted for each separate profile. In this instance, the exception is that the device registered in the SYSTEM\CurrentControlSet\Enum\ROOT\LEGACY_SMC1211 subkey of HKEY_LOCAL_MACHINE (which is the device associated with the driver whose configuration information is stored under \Services\SMC1211) should be disabled. SMC1211 happens to be the name of the Network Interface Card of the workstation on which we are currently working, hence, its significance.
There are three further points that should be noted:
- If you start up a workstation with networking disabled in this manner, look at the logs in Event Viewer. You will notice that disabling the NIC driver does not provoke the higher-level network services into complaining bitterly; this seems strange given that all sorts of services failed when the Workstation Service failed, and surely all network services depend upon the NIC driver! True, but there is an explanation: removing a driver from a hardware profile is not the same as allowing that driver to fail on startup. If a service or driver is actually disabled, the operating system does not even try to load other drivers and services that depend on it.
- It is essential that you carry out the preceding procedure yourself if you intend to manipulate network connectivity through the registry. Simply copying the key as printed earlier is highly unlikely to work. This is because the LEGACY_SMC1211 reference is specific to the network interface card that happens to be in our computer; a different card will yield a different key.
- It would have been completely impossible to “find” the preceding key by simply browsing the registry. The reason? The first time networking is disabled, it is not simply the value of CSConfigFlags that is toggled from 0x0 to 0x1; the key is actually created on the fly.
To end this chapter, we present a script that uses the fruits of our labor to control network connectivity. The code carries out exactly the same action as checking the Network-disabled Hardware Profile option from System Properties. First, it decides whether to enable or disable the network, basing its decision on a command-line parameter. Next it creates the key HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\0000\System\CurrentControlSet\Enum\ROOT\LEGACY_SMC1211\0000.
Note that we use the RegCreateKey function for this purpose.8 As has been seen, the key in question does not exist by default and so the first time you wish to disable networking it must be created. If the key does exist (which it will after you've run this script once), then the use of RegCreateKey still does not pose a problem; it simply opens the key and returns a handle to it. Next, the script sets the value CSConfigFlags. Finally, the key is closed and the user is given some simple feedback.
#ntctrl.pl - enables or disables networking use Win32::Registry;
Here, the value of the command-line argument is read, and the string passed is replaced with the corresponding numeric value that will need to be written to CSConfigFlags.
$data = shift @ARGV; if ($data eq "enabled") { $data = 0; } elsif ($data eq "disabled"){ $data = 1; } else {die "State not set. Parameters are - disabled or enabled\n"}; # The following three lines of code create the key (or open # it if it already exists), set the value, and close the key. # Note: the following code within the single quotes MUST be on # a single line i.e., NOT WRAPPED!! Win32::Registry::RegCreateKey (&HKEY_LOCAL_MACHINE,'\System\CurrentControlSet\Hardware Profiles \0000\System\CurrentControlSet\Enum\ROOT\ LEGACY_SMC1211\0000\CSConfigFlags ',$RegHandle) || die; Win32::Registry::RegSetValueEx ($RegHandle,'CSConfigFlags',NULL,®_DWORD,$data); Win32::Registry::RegCloseKey($RegHandle);
Finally, some feedback is displayed on standard output.
if ($data) { print "\nNetworking Disabled\n"; } else { print "\nNetworking Enabled\n"; }
To run the script, type the following at the command prompt with a single parameter, either enabled or disabled:
C:\>ntctrl.pl enabled
Of course, there is no particular advantage to running the script interactively over using the Control Panel. However, just as with any script, this can be run remotely, by a scheduler, or as part of a larger structure. The main purpose of the script is to illustrate a situation in which a service or driver needs to be controlled and in which registry monitoring is really the only way of achieving the desired goal. As we have already noted, browsing the registry for a likely looking key would be absolutely futile; you may well be searching for something nonexistent. A reference book would also be of little direct help here because the key to create is dependent on the make of your Network Interface Card. On the other hand, use of Regmon here has made a seemingly daunting task completely trivial.
Summary
We began this chapter by showing how the utility net.exe can be used with a minimum of fuss to start and stop NT services. This was followed by a demonstration of registry monitoring, a technique that facilitates the discovery of registry entries associated with various parameters that normally are configured through GUI components such as the Service Control Panel. Next was a discussion of the NT Event Viewer and how the information it presents relates to a series of registry values that are of particular interest to someone intending to control services and devices through scripting. Finally, we presented a scenario in which it might be desirable to disable all network services and showed how a technique already described could lead to the writing of a simple script that could accomplish this task. In the next chapter, we move on to consider how to write scripts that configure differentially, depending on the specific workstation upon which they are running. In conjunction with techniques learned in this chapter, this leads to a discussion hinted at earlier, namely, how to write a script that can configure a set of identical workstations with their own identities.
*Managing the Windows NT Registry, by Paul Robichaux (O'Reilly & Associates, 1998) provides fairly comprehensive coverage of the Windows NT registry, as does the NT Workstation Resource Kit.
*An alternative solution to using net.exe in this context would be to use the Perl module Win32::Service.
*To be fair to NT, it does inform you of this if you try to set registry auditing without having first established an audit policy, rather than simply failing quietly.
*The sysdiff utility does not necessarily record every single detail of the workstation, including all files and all registry entries on the system. The scope of its operation is configured in the sysdiff.inf file. Before using the utility for anything important, it is essential to check that the default configuration is adequate.
*One major gripe we have with sysdiff is that the command sydiff /?, which one might expect to provide a syntax summary, does nothing except pop up a dialog box complaining, “Incorrect arguments. Consult the Windows NT OEM Preinstall Kit documentation for a description of the arguments to this application.” This is hardly very user-friendly!
†The concerns here are equivalent to monitoring the entire registry with the auditing tool.
*The key current control set is a dynamically created symbolic link to the control set that is currently being used. Different control sets refer to different hardware profiles.
*This function will be discussed along with the other registry functions in the Appendix, Perl Module Functions.
Get Windows NT Workstation: Configuration and Maintenance now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.