Chapter 14. Processes

Everything that takes place on a computer is somehow connected to a process — a running instance of an application or executable file. Because processes underlie all the activities on a computer, it is important that you routinely monitor and manage processes and process performance. Doing so provides a window into how a computer is being used, enables you to quickly correct software-related problems, and even allows you to anticipate trouble before it occurs. These activities can be greatly facilitated by the scripting technologies available in the Microsoft® Windows® 2000 family of operating systems.

In This Chapter

Processes Overview

Users tend to think of software in terms of shrink-wrapped boxes bought at the local computer store. System administrators tend to think of software as something that needs to be installed, upgraded, and, on occasion, removed. Few people think of software as a dynamic entity that needs to be monitored and managed in the same way you need to monitor and manage such things as printers, disk drives, or services.

Managing software that is actually running, as opposed to software that is simply waiting to be installed, upgraded, or removed, is a very important, yet often overlooked, system administration task. This type of management (often referred to as process management) helps ensure that your computers run efficiently and effectively, and that they run legally as well. Software that is not running as expected might use up a disproportionate amount of system resources; in fact, a single errant process could exhaust all available memory and bring a computer to a halt. Unlicensed (and thus illegal) software running on a system might have ramifications that go much further.

Scripting can be used to help keep track of the software running on a computer, to help ensure that this software runs efficiently, and to stop and start software as needed. All of these activities fall under the umbrella of process management.

What Is a Process?

A process is a running instance of an application or executable file, along with all the system resources that have been allocated to that instance. In general, a process is equivalent to a single application or service; for example, Microsoft® Word runs in the Winword.exe process.

Note

Note

A script is not equivalent to a process. Instead, each script runs in an instance of the scripting host process; each time you run a VBScript script, an instance of either Wscript.exe or Cscript.exe is started. If you start five scripts, the Task Manager lists five instances of Wscript.exe. It does not list the names of the individual scripts running in each of these processes.

To a user, a process appears as a single entity (such as Winword.exe). The operating system, however, takes a very different view of processes. It is this view that helps explain how processes work and, equally important, what happens when they do not work.

How Processes Work

Each process is composed of a set of threads. A thread is a unit of work that runs simultaneously with other units of work on the computer; each process must have at least one thread.

Threads represent the basic unit of execution in the Windows 2000. When a thread starts, the Windows 2000 Memory Manager allocates enough physical memory and page file space to allow the thread to run. While a thread is running, it can request additional memory to enable it to complete its task. When a thread ends, it releases the memory it was using back to the Memory Manager for reallocation.

Memory is also allocated based on the number of threads spawned by each process. For example, consider a computer running two processes. Process A has 5 threads, and Process B has 15 threads. Assuming the two processes have equal priority, Process A is allocated 25 percent (5 / 20) of the memory being used and Process B is allocated 75 percent (15 / 20) of the memory being used.

This method of thread allocation helps ensure that applications receive the memory they need. However, this same method can also result in memory leaks. A memory leak occurs when an application receives an increasing amount of memory but does not relinquish that memory back to the Memory Manager. This typically happens when a process creates threads but does not destroy those threads when they have finished their work. This disrupts memory allocation in two ways:

  • Each thread that is created is allocated a certain amount of memory. If the thread is not destroyed, that memory is retained by the process and is not reallocated.

  • The number of threads created by a process determines how much memory is allocated to the process. If a process continually creates threads without destroying them, the number of threads owned by that process keeps increasing and the process receives a disproportionate share of memory.

If left unchecked, a single process can eventually exhaust the supply of available memory, causing the system to fail. This alone provides an important reason for carefully monitoring and managing the processes running on your computers.

Managing Processes

Processes underlie almost everything that happens on a computer. In fact, the root cause of most computer problems can be traced to processes; for example, too many processes might be running on a computer (and contending for a finite set of resources), or a single process might be using more than its share of resources.

These factors make it important to keep a close watch on the processes running on a computer. Process monitoring, the main activity in process management, allows you to determine what a computer actually does, what applications the computer runs, and how those applications are affected by changes in the computing environment.

Process monitoring helps you:

  • Optimize your system to account for peak demands.

    For example, you can ensure that a backup service runs only at night, when the high network utilization does not adversely affect users.

  • Identify and react to potential problems.

    Monitoring memory use can help you identify memory leaks and enable you to take action before an application can monopolize system resources and bring the computer to a halt.

  • Ensure that computers are being used properly.

    For example, by monitoring the processes running on a computer, you know whether an administrator has started a resource-intensive application on a Domain Name System (DNS) server.

In addition to monitoring processes, process management also includes such tasks as creating processes, terminating processes, and configuring process priority.

Processes can be managed by using the graphical user utility Windows Task Manager. However, Task Manager returns information only about the processes running on the local computer and cannot be used as part of an automated management strategy. Fortunately, the Windows Management Instrumentation (WMI) Win32_Process class can retrieve much of the same information and carry out many of the same tasks as Task Manager. A comparison of selected Win32_Process classes and methods and the Windows Task Manager is shown in Figure 14.1.

Win32_Process and Windows Task Manager

Figure 14.1. Win32_Process and Windows Task Manager

Monitoring Processes

Monitoring processes on a regular basis helps you ensure that a computer runs at peak efficiency and that it carries out its appointed tasks as expected. For example, by monitoring processes you can be notified immediately of any application that has stopped responding, and then take steps to end that process. In addition, process monitoring enables you to identify problems before they occur. For example, by repeatedly checking the amount of memory used by a process, you can identify a memory leak. You can then stop the process before the errant application uses all of the available memory and brings the computer to a halt.

Process monitoring also helps minimize the disruptions caused by planned outages for upgrades and maintenance. For example, by checking the status of a database application running on client computers, you can determine the impact of taking the database offline in order to upgrade the software.

Process monitoring can be divided into three general categories:

  • Monitoring process availability. Measures the percentage of time that a process is available.

    Availability is typically monitored by use of a simple probe, which reports whether the process is still running. By keeping track of the results of each probe, you can calculate the availability of the process. For example, a process that is probed 100 times and responds on 95 of those occasions has an availability of 95 percent.

    This type of monitoring is typically reserved for databases, mail programs, and other applications that are expected to run at all times. It is not appropriate for word processing programs, spreadsheets, or other applications that are routinely started and stopped several times a day.

  • Monitoring process reliability. Measures how frequently a process fails, and the amount of time required to restart a failed process.

    Reliability is calculated by dividing the time the process is functioning by the total number of days in a year. For example, a process that experiences a total downtime of 2 days during the course of a year is 99.5 percent reliable (363 days of availability divided by 365 days in a year).

    This type of monitoring is also reserved for databases, mail programs, and other applications that are expected to run at all times. It is not appropriate to measure reliability for word processing programs, spreadsheets, or other applications that are routinely started and stopped several times a day.

  • Monitoring process performance. Measures whether the process runs in the expected manner.

    Performance monitoring is typically done by tracking memory use and threads. In general, a process should show a pattern of being allocated additional memory as needed and then releasing that memory when it is no longer needed. Likewise, a process should continually be creating and destroying threads. If memory is allocated but not released, or threads are created but not destroyed, this is usually an indication of a memory leak or another problem. Performance should be a series of peaks and valleys rather than a steady incline.

Monitoring Processes for Availability

Availability is the simplest form of process monitoring: with this approach, you simply ensure that the process is running. When you monitor for process availability, you typically retrieve a list of processes running on a computer and then verify that a particular process is still active. If the process is active, it is considered available. If the process is not active, it is not available.

The Win32_Process class enables you to create scripts that identify the processes currently running on any computer in your organization.

Scripting Steps

Listing 14.1 contains a script that monitors process availability by checking the list of processes running on a computer and issuing a notification if the Database.exe process is not found. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_Process class.

    To restrict data retrieval to a single process, a WHERE clause is used to limit data retrieval to the process with the name Database.exe.

  4. Use the Count method to determine the number of processes retrieved.

    The Count method provides a quick way to determine whether Database.exe is running. If Count is equal to 1, that means one instance of Database.exe is running on the computer. If Count is equal to 0, no instances of Database.exe are running on the computer.

  5. If no instances of Database.exe are detected, a message to that effect is echoed to the screen. Otherwise, the script echoes the fact that Database.exe is running.

Example 14.1. Monitoring Process Availability

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colProcesses = objWMIService.ExecQuery _
 5     ("SELECT * FROM Win32_Process WHERE Name = 'Database.exe'")
 6 If colProcesses.Count = 0 Then
 7     Wscript.Echo "Database.exe is not running."
 8 Else
 9     Wscript.Echo "Database.exe is running."
10 End If

Monitoring Processes for Reliability

Reliability measures the mean time between failures for an application; that is, how long an application runs before it fails. For many applications, attempting to measure this type of reliability is irrelevant. For example, Microsoft Word typically runs only as long as a user needs it. When finished, the user closes Word. The fact that Word might be running only for a few minutes does not necessarily tell you anything about the reliability of the application. Instead, it typically indicates only that the user simply did something — such as open a document and print it — and then closed Word.

Other applications, such as many database applications, are designed to run continuously. For these applications, reliability measurements are much more meaningful. You can use WMI event subscriptions to help monitor the reliability of those processes.

Event subscriptions can notify you any time a process is created or deleted on a computer. This allows you to carry out reliability monitoring: you can record the time each process is created and the time each process is deleted, and then calculate the reliability of the application (the amount of time that elapsed between process creation and deletion).

Monitoring process creation and deletion also provides a rudimentary but useful way to monitor software use in your organization. You can use this approach to keep track of the number of times software applications are started and to determine the length of a typical application session. This provides you with a rough estimate of which programs are used most often, and for how long.

You can also use process creation monitoring to help control the services and applications that run on a computer. For example, in an enterprise setting, servers are typically dedicated to single tasks, such as allocating IP addresses or managing print queues. By monitoring process creation, you can be notified immediately any time a different service or application starts on one of these servers.

In addition to keeping track of each time a process is created, you can use WMI to keep track of each time a process is deleted. Monitoring process deletion helps you ensure that critical applications remain running at all times. For example, you might write a script that monitors a database application on a computer. If the application fails, the process is deleted. The script can identify the fact that the database process no longer exists and automatically restart the application.

Note

Note

By monitoring process deletion, you can determine that an application has finished running. However, you cannot determine whether the application finished running because a user closed it or because it failed.

Scripting Steps

The scripts for monitoring process creation and process deletion are similar.

Monitoring process creation

Listing 14.2 contains a script that monitors process creation using a temporary event consumer. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer and set the impersonation level to “impersonate.”

  3. Use the ExecNotificationQuery method to register for notification each time there is an instance creation (each time a new instance is created within the namespace).

    To restrict data retrieval to processes, a WHERE clause is included to limit data retrieval to instance creations involving the Win32_Process class (WHERE TargetInstance ISA ’Win32_Process’).

  4. Create a loop that allows the script to run indefinitely.

    To stop monitoring, you need to either log off the computer or terminate the process the script is running in.

  5. Use the NextEvent method to retrieve the properties of each event when it occurs.

  6. Each time a process is created, echo the name of that process and the current time (Now). The current time indicates the time the process was created.

Example 14.2. Monitoring Process Creation

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colMonitoredProcesses = objWMIService. _
 5     ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent " _
 6         & "WITHIN 10 WHERE TargetInstance ISA 'Win32_Process'")
 7 i = 0
 8 Do While i = 0
 9     Set objLatestProcess = colMonitoredProcesses.NextEvent
10     Wscript.Echo objLatestProcess.TargetInstance.Name, Now
11 Loop

Monitoring process deletion

To monitor process deletion, use a script similar to Listing 14.2 but substitute __InstanceDeletionEvent for __InstanceCreationEvent in the ExecNotificationQuery, as shown in Listing 14.3.

Example 14.3. Monitoring Process Deletion

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colMonitoredProcesses = objWMIService. _
 5     ExecNotificationQuery("SELECT * FROM __InstanceDeletionEvent " _
 6         & "WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'")
 7 i = 0
 8 Do While i = 0
 9     Set objLatestProcess = colMonitoredProcesses.NextEvent
10     Wscript.Echo objLatestProcess.TargetInstance.Name, Now
11 Loop

Monitoring Processes for Performance

Performance monitoring is typically directed at entire systems; for example, administrators often monitor such things as the available bytes of memory or total processor use on a computer. This kind of monitoring is extremely useful because it identifies problems, such as rapid diminution of available memory, that can have a detrimental effect on the performance of the computer itself. However, monitoring performance of the system as a whole typically does not indicate why memory is diminishing. To help answer that question, you can monitor the performance of individual processes.

Monitoring the performance of individual processes is particularly useful when you are trying to identify memory leaks. To help diagnose memory leaks in Windows 2000, you can monitor several process properties, including:

  • Threads and pool space. If a process is leaking memory, the number of threads owned by the process and the amount of pool space used increase in a stair-step pattern. The usage of both threads and pool space remain flat for a while, jump dramatically, and then remain flat again. This pattern can repeat indefinitely, with threads and pool space both increasing over time. If a process releases threads and pool space appropriately, these totals remain relatively stable over time.

  • Working set size. The working set is the amount of physical memory assigned to a process. If the working set is too small, the process incurs a high number of page faults as it repeatedly accesses the disk drive to locate data not currently in memory. If the working set is too large, fewer page faults occur, but the process retains memory that it no longer needs, and which might be required by other processes. A steady increase in the size of the working set can mean that the process is not releasing memory appropriately.

  • Page file bytes. Page file bytes typically correspond to memory consumption. Memory leaks often cause a similar increase in both the working set size and the page file bytes.

  • Processor use. Processor use is determined in part by the number of threads allocated to a process. A process that is not destroying threads receives a disproportionate amount of processor time.

All of these key indicators of process performance can be monitored by using WMI. A list of important process properties available through the Win32_Process class is shown in Table 14.1.

Table 14.1. WMI Win32_Process Properties

Property

Description

ExecutablePath

Local path to the executable file.

ExecutionState

Current status of the process. Valid values are:

  • 0— Unknown

  • 1— Other

  • 2— Ready

  • 3— Running

  • 4— Blocked

  • 5— Suspended Blocked

  • 6— Suspended Ready

KernelModeTime

Kernel mode usage, in milliseconds.

Name

Name of the executable file responsible for the process, equivalent to the Image Name property in Task Manager.

The name is hard-coded into the application itself and is not affected by changing the file name. For example, even if you rename Calc.exe, the name Calc.exe will still appear in Task Manager and in any WMI scripts that retrieve the process name.

PageFaults

Number of page faults generated by the process.

PageFileUsage

Amount of page file space (in kilobytes) currently used by the process.

PeakWorkingSetSize

Maximum size of the working set (in kilobytes) used by the process since it was created.

Priority

Scheduling priority of the process. Priorities range from 0 (lowest priority) to 31 (highest priority).

ProcessID

Numeric identifier used to distinguish one process from another. ProcessIDs are valid from process creation time to process termination. Upon termination, that same numeric identifier can be applied to a new process.

This means that you cannot use ProcessID alone to monitor a particular process. For example, an application could have a ProcessID of 7, and then fail. When a new process is started, the new process could be assigned ProcessID 7. A script that checked only for a specified ProcessID could thus be “fooled” into thinking that the original application was still running.

QuotaNonPagedPoolUsage

Quota of nonpaged pool usage available to the process.

QuotaPagedPoolUsage

Quota of paged pool usage available to the process.

ThreadCount

Number of active threads associated with a process. Each process must have at least one thread.

UserModeTime

User mode usage (in milliseconds).

WorkingSetSize

Amount of memory (in bytes) the process needs to execute efficiently. If adequate memory is not available, “disk thrashing” occurs. (Disk thrashing refers to those times when the operating system must repeatedly access the hard disk.)

Scripting Steps

Process performance can be monitored in several different ways, including:

  • Monitoring process performance information (memory use, page file use, and threads created) for each individual process.

  • Monitoring processor use by process.

Monitoring process performance information

Listing 14.4 contains a script that monitors process performance information. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_Process class. This returns a collection consisting of all the processes running on the computer.

  4. For each process in the collection, echo the following information:

    • Process name

    • Process ID

    • Thread count

    • Page file use

    • Total page faults

    • Current working set size

Example 14.4. Monitoring Process Performance

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colProcessList = objWMIService.ExecQuery _
 5     ("SELECT * FROM Win32_Process")
 6 For Each objProcess in colProcessList
 7     Wscript.Echo "Process: " & objProcess.Name
 8     Wscript.Echo "Process ID: " & objProcess.ProcessID
 9     Wscript.Echo "Thread Count: " & objProcess.ThreadCount
10     Wscript.Echo "Page File Size: " & objProcess.PageFileUsage
11     Wscript.Echo "Page Faults: " & objProcess.PageFaults
12     Wscript.Echo "Working Set Size: " & objProcess.WorkingSetSize
13 Next

The script shown in Listing 14.4 is designed to display process information once and then terminate. Alternatively, you might want to view process performance over time. To do this, include a For-Next loop in your script, and use the Wscript.Sleep command to pause the script for the appropriate interval. For example, the script shown in Listing 14.5 runs 10 times, displaying the current process data each time, and pauses 60 seconds (60,000 milliseconds) before retrieving updated process information.

Example 14.5. Monitoring Process Performance Over Time

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 For i = 1 to 10
 5 Set colProcessList = objWMIService.ExecQuery
 6     ("SELECT * FROM Win32_Process")
 7     For Each objProcess in colProcessList
 8         Wscript.Echo "Process: " & objProcess.Name
 9         Wscript.Echo "Process ID: " & objProcess.ProcessID
10         Wscript.Echo "Thread Count: " & objProcess.ThreadCount
11         Wscript.Echo "Page File Size: " & objProcess.PageFileUsage
12         Wscript.Echo "Page Faults: " & objProcess.PageFaults
13         Wscript.Echo "Working Set Size: " & objProcess.WorkingSetSize
14     Next
15     Wscript.Echo
16     Wscript.Sleep 60000
17 Next

Monitoring processor use

Listing 14.6 contains a script that monitors processor use by process. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_Process class. This returns a collection consisting of all the processes running on the computer.

  4. For each process in the collection, calculate the total processor use.

    1. Add the values for KernelModeTime and UserModeTime.

      Together, KernelModeTime and UserModeTime tell you the total amount of processor time allocated to a process. To ensure that these values are added and not concatenated, use the VBScript function CSng to convert the variant data to the single data type.

    2. Divide the combined value by 10,000,000.

      Processor use times are reported in 100-nanosecond increments. (A nanosecond is one-billionth of a second; 100 nanoseconds equal one ten-millionth of a second.) This calculation results in processor use being reported in seconds.

  5. Echo the process name and total processor use.

Example 14.6. Monitoring Processor Use by Process

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colProcesses = objWMIService.ExecQuery _
 5     ("SELECT * FROM Win32_Process")
 6 For Each objProcess in colProcesses
 7     sngProcessTime = (CSng(objProcess.KernelModeTime) + _
 8         CSng(objProcess.UserModeTime)) / 10000000
 9     Wscript.Echo objProcess.Name & VbTab & sngProcessTime
10 Next

Displaying Current Process Performance Data

Although many system administration scripts run in a command window, the command window is not always suitable for displaying process performance data. Within a command window, there are few options for formatting data: you are limited to a single nonproportional font, with each character the same size and color. In addition, data within the command window cannot be cleared by using a script. Neither Windows Script Host (WSH) nor VBScript provides methods for clearing the screen; although you can call the command-line utility cls from within a script, instead of the current command window being cleared a second command window opens, and the cls command is carried out there.

The inability to clear a command window has important implications for scripts that monitor process status or process performance. You cannot display the current process status, wait a few minutes, and then erase that data and replace it with updated status information. Instead, each time you retrieve process information, the new data is appended to the end of the existing data. While this large collection of data might be useful for viewing process performance over time, it is far less useful if you simply want to view the current state of each process running on a computer.

As an alternative to displaying process performance in a command window, you can use a hypertext application (HTA) that allows you to display process information on a Web page. Displaying process data in an HTA offers the following advantages:

  • You can clear the page each time the latest set of data is retrieved so that the page displays only the current process information.

  • You can use additional formatting to highlight important items. For example, you might use a different font color to indicate a process that has a working set size greater than a specified amount.

An HTA is a Web page that has the file name extension .HTA. HTAs are useful for script writers because they can use Automation objects that have not been marked as safe for scripting. This allows you to use WMI within a Web page.

For more information about HTAs, see “Creating Enterprise Scripts” in this book.

Scripting Steps

Listing 14.7 contains the HTML tags and VBScript code required to create an HTA that displays process performance information on a Web page. Type this information into a text editor, and then save it with the .HTA file name extension.

To carry out the task of displaying process performance information on a Web page, the HTA must perform the following steps:

  1. Create a <SCRIPT> tag specifying VBScript as the scripting language.

  2. Create a constant named USE_COMMAS.

    This constant is used to format the working set value for each process.

  3. Create a window_onLoad subroutine.

    Code in the window_onLoad subroutine automatically runs whenever the window is loaded (either through initial startup or by clicking the browser Refresh button).

  4. Use the setInterval method to create a timer that updates the list of running processes every 10 seconds.

    The setInterval method requires three parameters:

    • GetInfo. The name of the subroutine called by the timer.

    • 10000. Number of milliseconds between calls. The timer calls the GetInfo subroutine, waits 10 seconds, and then calls the subroutine again.

    • VBScript. Scripting language used by the GetInfo script.

    The setInterval method provides functionality similar to Wscript.Sleep: It allows you to pause the script for a specified amount of time and then resume processing. This method must be used instead of Wscript.Sleep because Windows Script Host (WSH) methods cannot be called from Internet Explorer.

  5. Create a subroutine named GetInfo that retrieves the current set of processes and displays the process information in a table.

    To do this, the GetInfo subroutine must first delete the current version of the table (if one exists), create the table header, retrieve the process information, and then display the process information in the table.

  6. Create a loop that deletes all the rows in the existing table (with the Table ID of objTable).

    Deleting the current table has the effect of wiping the page clean, allowing the latest process information to be displayed.

    The loop works backward from the last row in the table (Rows.Length — 1) to the first row in the table (row 0). If there are three rows in the table, row 2 is deleted first, then row 1, and then row 0.

  7. Create the table header.

    To do this, the script must:

    • Use the InsertRow method to insert a new row in the table.

    • Use the InsertCell method to insert a new cell in the table.

    • Use the InnerText method to set the contents of the new cell to Process ID.

    • Use the same procedures to insert cells labeled Process Name and Working Set Size.

  8. Create a variable to specify the computer name.

  9. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  10. Use the ExecQuery method to query the Win32_Process class. This query returns a collection consisting of all the processes running on the computer.

  11. For each process in the collection, create a new row with three cells to display the following: process ID, process name, and working set size.

    The FormatNumber function is used to insert comma delimiters in the working set values. By using this function, numbers are displayed with thousands separators, such as 3,456,789 rather than 3456789. The FormatNumber function requires the following parameters:

    • StrProcess.WorkingSetSize. Value to be formatted.

    • 0. Indicates the number of digits displayed after the decimal point. A 0 indicates that the decimal point should not be used.

    • Empty. Used to display a leading 0 for fractional values. Not applicable for this script.

    • Empty. Used to place parentheses around negative values. Not applicable for this script.

    • USE_COMMAS. Constant that indicates whether numbers are grouped using the group delimiter specified in Control Panel. For U.S. English, this is typically the comma. You can find the default delimiter for a computer by opening the Regional and Language Options Control Panel, clicking the Numbers tab, and then checking the value in the Digit grouping symbol box.

  12. Create a <TABLE> tag with the ID objTable. In addition, include the Border = 1 parameter to place a border around each cell in the table.

  13. Create a <TBODY> tag with the ID objTableBody.

    This tag is used to represent the actual body of the table.

Example 14.7. Displaying Process Performance on a Web Page

 1 <SCRIPT LANGUAGE = "VBScript">
 2 Sub window_onLoad
 3     iTimerID = window.setInterval("GetInfo", 10000, "VBScript")
 4 End Sub
 5 Sub GetInfo
 6     For i = (objTable.Rows.Length - 1) to 0 Step -1
 7         myNewRow = document.all.objTable.deleteRow(i)
 8     Next
 9     Set objRow = objTableBody.InsertRow()
10     objRow.Style.fontWeight = "bold"
11     Set objCell = objRow.InsertCell()
12     objCell.InnerText = "Process ID"
13     Set objCell = objRow.InsertCell()
14     objCell.InnerText = "Process Name"
15     Set objCell = objRow.InsertCell()
16     objCell.InnerText = "Working Set Size"
17     strComputer = "."
18     Set objWMIService = GetObject("winmgmts:" _
19         & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
20     Set colProcesses = objWMIService.ExecQuery _
21         ("SELECT * FROM Win32_Process")
22     For Each strProcess in colProcesses
23         Set objRow = objTableBody.InsertRow()
24         Set objCell = objRow.InsertCell()
25         objCell.InnerText = strProcess.ProcessID
26         Set objCell = objRow.InsertCell()
27         objCell.InnerText = strProcess.Name
28         Set objCell = objRow.InsertCell()
29         objCell.InnerText = FormatNumber(strProcess.WorkingSetSize,0,,,-1)
30     Next
31 End Sub
32 </SCRIPT>
33 <TABLE ID = "objTable">
34 <TBODY ID = "objTableBody">
35 </TBODY>
36 </TABLE>

The finished HTA appears similar to Figure 14.2. Every 10 seconds, the display is replaced with updated process information.

Process Performance Data Displayed on a Web Page

Figure 14.2. Process Performance Data Displayed on a Web Page

Enumerating Additional Process Properties

In addition to basic process properties such as executable path name and working set size, WMI scripts can retrieve additional properties for each process. These additional properties include such things as:

  • Information about the process owner (the account name under which the process is running).

  • Information about each thread in the process.

Although rarely needed for routine monitoring, these properties can be useful in diagnosing problems. Monitoring each thread in a process can help verify that an application is leaking memory. Knowing who owns a process tells you who is running an application on a computer. This information can also be useful when helping remote users terminate processes. Users can terminate only those processes that run under their user account; if a user is unable to stop a process on his or her computer, it might be because the process is running under a different account.

Determining Process Owners

Because processes represent such things as software applications or services, they need to carry out actions on a computer. For example, a process might write data to a particular folder, modify a specific registry key, or connect to a remote computer. The ability of a process to carry out these actions depends on the security context under which the action is attempted. Processes generally run under the security context of the user who started the process. (This user is known as the process owner.) If the user account that owns the process has the appropriate access rights, the action succeeds; if it does not, the action fails.

By identifying the owner of a process, you can tell which account the process is running under. This information can help you:

  • Identify users who have remotely created processes on a computer.

  • Determine whether a specific user can terminate a specific process. By default, users can terminate only those processes that they themselves have started.

  • Create scripts that automatically terminate all the processes owned by a specified user.

To retrieve the owner of a process, use the Win32_Process class GetOwner method. GetOwner returns the user account name for the process owner as well as the domain for that user account.

Scripting Steps

Listing 14.8 contains a script that determines the owner of each process running on a computer. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_Process class. This returns a collection consisting of all the processes running on the computer.

  4. For each process in the collection, use the GetOwner method to determine the user name and domain for the process.

  5. Echo the name of the process and its owner by using the following format:

    Process Winword.exe is owned by Fabrikamkmyer.
    

Example 14.8. Determining Process Ownership

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colProcessList = objWMIService.ExecQuery _
 5     ("SELECT * FROM Win32_Process")
 6 For Each objProcess in colProcessList
 7     colProperties = objProcess.GetOwner(strNameOfUser,strUserDomain)
 8     Wscript.Echo "Process " & objProcess.Name & " is owned by " _
 9         & strUserDomain & "" & strNameOfUser & "."
10 Next

Monitoring Threads

For routine day-to-day monitoring, there is usually little reason to have a detailed list of threads and their associated properties. Computers create and delete thousands of threads during the course of a day, and few of these creations or deletions are meaningful to anyone but the developer who wrote the software.

However, when you are troubleshooting problems with an application, tracking the individual threads for a process allows you to identify when threads are created and when (or if) they are destroyed. Because threads that are created but not destroyed cause memory leaks, tracking individual threads can be useful information for support technicians. Likewise, identifying thread priorities can help pinpoint threads that, by running at an abnormally high priority, are preempting CPU cycles needed by other threads and other processes.

For occasions such as this, you can use the Win32_Thread class to return information about all the threads on a computer. Some of the more useful properties of the Win32_Thread class are shown in Table 14.2.

Table 14.2. Win32_Thread Properties

Property

Description

ElapsedTime

Total execution time, in milliseconds, allotted to this thread since its creation.

Handle

Identifier assigned by the operating system to the thread.

KernelModeTime

Kernel-mode time used by the thread, in 100-nanosecond increments.

Priority

Dynamic priority of the thread.

Each thread has a dynamic priority that the scheduler uses to determine which thread to execute. Initially, a thread’s dynamic priority is the same as its base priority. The operating system can raise and lower the dynamic priority to ensure that the computer remains responsive (guaranteeing that no threads are starved for processor time).

PriorityBase

Current base priority of a thread. The operating system can raise the thread’s dynamic priority above the base priority if the thread is handling user input, or lower it toward the base priority as needed. The PriorityBase property can have a value between 0 and 31.

ProcessHandle

Process ID for the process that spawned the thread. This is the only way to tie an individual thread to its parent process.

ThreadState

Current execution state for the thread. Values include:

  • 1— Initialized

  • 2— Ready

  • 3— Running

  • 4— Standby

  • 5— Terminated

  • 6— Waiting

  • 7— Transition

  • 8— Unknown

UserModeTime

User-mode time used by the thread, in 100-nanosecond increments.

As implied in the preceding table, the Win32_Thread class does not report the name of the process under which each thread runs. Instead, it reports the ID of the process under which the thread runs. To return the name of a process and a list of all its threads, your script must:

  1. Connect to the Win32_Process class and return the list of processes and their process IDs.

  2. Temporarily store this information in an array or Dictionary object.

  3. For each process ID, return the list of threads for that process, and then display the process name and the list of threads.

Scripting Steps

Listing 14.9 contains a script that monitors the threads running on a computer. To carry out this task, the script must perform the following steps:

  1. Create a Dictionary object that is used to store process names and IDs.

  2. Create a variable to specify the computer name.

  3. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  4. Use the ExecQuery method to query the Win32_Process class. This returns a collection consisting of all the processes running on the computer.

  5. For each process in the collection, add the process ID and process name to the Dictionary. As a result, the Dictionary will contain entries such as these:

    Clisvcl.exe   564
    
    Crss.exe   168
    
    Explorer.exe   1728
    
  6. Use the ExecQuery method to retrieve the list of running threads from the Win32_Thread class. This returns a collection consisting of all the threads running on the computer.

  7. For each thread in the collection, retrieve the ProcessHandle.

    The ProcessHandle represents the process ID of the process that created the thread. This is used to identify the threads that belong to each process. Because the process IDs are stored in the Dictionary as integers, the VBScript function CInt is used to ensure that the ProcessHandle is stored in the variable intProcessID as an integer.

  8. Use the variable intProcessName to query the Dictionary and return the name of the process corresponding to that process ID.

    This step is required because the Win32_Thread class maintains only the ID of the process that created the thread; it does not maintain information about the name of the process. Including this step allows you to determine the threads that are running under processes such as Winword.exe rather than threads that are running under a process ID such as 599.

  9. Echo the name of the process, the process ID, the thread ID, and the current thread state.

Example 14.9. Monitoring Threads

 1 Set objDictionary = CreateObject("Scripting.Dictionary")
 2 strComputer = "."
 3 Set objWMIService = GetObject("winmgmts:" _
 4     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 5 Set colProcesses = objWMIService.ExecQuery _
 6     ("SELECT * FROM Win32_Process")
 7 For Each objProcess in colProcesses
 8     objDictionary.Add objProcess.ProcessID, objProcess.Name
 9 Next
10 Set colThreads = objWMIService.ExecQuery _
11     ("SELECT * FROM Win32_Thread")
12 For Each objThread in colThreads
13     intProcessID = CInt(objThread.ProcessHandle)
14     strProcessName = objDictionary.Item(intProcessID)
15     Wscript.Echo strProcessName & VbTab & objThread.ProcessHandle & _
16         VbTab & objThread.Handle & VbTab & objThread.ThreadState
17 Next

Creating and Terminating Processes

To develop a complete process management system using WMI, you must be able to create and terminate processes. Among other things, this allows you to create scripts that:

  • Monitor for process availability and, if necessary, restart a process that has abnormally terminated.

  • Monitor for process performance and terminate a process that has exceeded specified thresholds.

  • Start a program on a remote computer and, when finished, terminate the program.

The Win32_Process class contains two methods, Create and Terminate, that can be used to create and terminate processes.

Creating Processes

The WMI Win32_Process Create method allows you to create processes on either the local computer or a remote computer. This is similar to Windows Script Host (WSH) version 5.6, which also allows you to create processes on either the local computer or a remote computer (using the WSHController object).

For the most part, WSH provides a simpler approach for starting processes on the local computer. For example, these two lines represent all the code needed to start a hypothetical application named Database.exe:

Set objShell = CreateObject("Wscript.Shell")
objShell.Run "database.exe"

When you need to create a process on remote computers, however, Win32_Process Create has the following advantages:

  • The Win32_Process Create method works on any computer running any version of WMI. By contrast, WSH requires you to configure both computers to allow for the use of the WSHController object, and it works only if WSH 5.6 has been installed on both computers.

  • You can create the process using a single script. WSH, by contrast, needs two scripts to start a remote process: a script on the remote computer that starts the process and a script on the local computer that starts the remote script.

  • You can retrieve the process ID for the created process; this allows you to monitor the process and, if necessary, terminate it. By contrast, WSH can monitor and terminate only the script that launched the new process, not the process itself.

  • You can specify additional options (such as priority and window style) when starting an application.

Scripting Steps

Listing 14.10 contains a script that creates a process on a remote computer. To carry out this task the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

    By specifying the class name as part of the call, the script is connected directly to the Win32_Process class on the remote computer.

  3. Use the Create method to create a new process on the remote computer, and specify the following parameters:

    • Database.exe. Name of the executable file to be started. If the file is in the computer’s path, only the name must be specified; otherwise, you must specify the entire path name relative to the computer where the process runs. To start a script remotely, as opposed to an executable file, specify the script host as part of the name (for example, “Wscript.exe MyScript.vbs”).

    • USE_SAME_STARTUP_FOLDER. Constant indicating the startup folder for the new process. The value Null is assigned to this constant to indicate that the new process should use the same startup folder as the script that created the process. This parameter is typically used for command-line applications and scripts that must reference a particular drive or folder when starting.

    • NO_STARTUP_OPTIONS. Constant indicating that there are no special startup options for the process. For more information about these options, see Modifying Process Startup Options later in this chapter.

    • intProcessID. If the Create method succeeds, the value of this variable is set to the process ID assigned to the remote process.

  4. Return an error code of 0 if the process is successfully created, and echo the process ID assigned to the new process.

  5. Return an error code other than 0 if the process could not be created, and echo that error code.

Example 14.10. Creating a Process on a Remote Computer

 1 strComputer = "webserver"
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & _
 4         "
ootcimv2:Win32_Process")
 5 errReturn = objWMIService.Create("database.exe", null, null, intProcessID)
 6 If errReturn = 0 Then
 7     Wscript.Echo "Database.exe was started with a process ID of " _
 8          & intProcessID & "."
 9 Else
10     Wscript.Echo "Database.exe could not be started due to error " & _
11         errReturn & "."
12 End If

Modifying Process Startup Options

The Win32_Process Create method enables you to configure startup options for any new process running on a computer. For example, you can configure a process so that it starts in a “hidden” window, which prevents a user from seeing, and possibly interrupting, it. If the process runs in a command window, you can configure the size, title, and foreground and background colors of the window.

Startup options are configured using the Win32_ProcessStartup class. Win32_ProcessStartup is a Method Type class; the Method Type class exists solely to pass information to a method. In this case, all the properties of an instance of Win32_ProcessStartup are passed to an instance of Win32_Process.

To configure a startup option by using Win32_ProcessStartup:

  1. Create an instance of Win32_ProcessStartup.

  2. Configure the properties of the new instance.

  3. Include the instance as part of the Win32_Process Create method.

For example, if you have created a Win32_ProcessStartup instance named objConfig, you would pass the object name in the Create method as follows:

errReturn = objProcess.Create("Database.exe", null, objConfig, intProcessID)

A partial list of startup options that can be configured using the Win32_ProcessStartup class is shown in Table 14.3.

Table 14.3. Process Startup Properties Available Through the Win32_ProcessStartup Class

Startup Option

Description

FillAtrribute

Initial text and background colors if the process runs in a command window. These values are ignored in graphical user interface (GUI) applications.

Valid values are:

  • 1— Foreground blue

  • 2— Foreground green

  • 4— Foreground red

  • 8— Foreground intensity

  • 16— Background blue

  • 32— Background green

  • 64— Background red

  • 128— Background intensity

To specify both foreground and background colors, add the values together. For example, to have red type (4) on a blue background (16), set the FillAttribute to 20.

PriorityClass

Priority class of the new process (used to determine the scheduling priorities of the threads in the process). Values are:

  • 32— Normal

  • 64— Low

  • 128— High

  • 16384— Below Normal

  • 32768— Above Normal

ShowWindow

State of the window as it appears to the user. Valid values are:

  • 1— Window is shown minimized

  • 3— Window is shown maximized

  • 5— Window is shown in normal view

  • 12— Window is hidden and not displayed to the user

Title

Text to be displayed in the title bar of a command window where the process runs. If not specified, the name of the executable file is used as the window title instead.

This property is ignored by processes that do not create a new command window.

XCountChars

Screen buffer width in character columns. This property is used for processes that create a command window but is ignored in GUI processes.

XSize

Width, in pixels, of the window, if a new window is created.

YCountChars

Screen buffer height in character rows. This property is used for processes that create a command window but is ignored in GUI processes.

YSize

Height, in pixels, of the window if a new window is created.

Scripting Steps

You can use the Win32_ProcessStartup class to configure various startup options for a process. These options include, but are not limited to, such things as creating a process in a hidden window and creating a higher-priority process.

Creating a process in a hidden window

Listing 14.11 contains a script that creates a process in a hidden window. To carry out this task, the script must perform the following steps:

  1. Create a constant named HIDDEN_WINDOW, and set the value to 12. This is the value required to start a process in a hidden window.

  2. Create a variable to specify the computer name.

  3. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  4. Get an instance of the Win32_ProcessStartup class.

  5. Use the SpawnInstance_ method to create a new, “blank” instance of Win32_ProcessStartup. The new instance, named objConfig, stores the startup properties of the process to be created.

  6. Set the ShowWindow property of the new instance to HIDDEN_WINDOW.

  7. Use a second GetObject call to get an instance of Win32_Process.

  8. Create the new process using the CreateProcess method.

    The first three parameters in the method specify the name of the executable file (such as Database.exe), the name of the startup folder (specifying Null gives the new process the same startup folder as the script that called the process), and the startup properties previously stored in objConfig.

    The fourth parameter (intProcessID) is a variable that represents the Process ID assigned to the new process. You can use this ID to monitor and, if necessary, terminate the process programmatically. This is especially useful for a process that runs in a hidden window and thus provides no visual cue to indicate that it is still running.

Example 14.11. Creating a Process in a Hidden Window

 1 Const HIDDEN_WINDOW = 12
 2 strComputer = "."
 3 Set objWMIService = GetObject("winmgmts:" _
 4     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 5 Set objStartup = objWMIService.Get("Win32_ProcessStartup")
 6 Set objConfig = objStartup.SpawnInstance_
 7 objConfig.ShowWindow = HIDDEN_WINDOW
 8 Set objProcess = GetObject("winmgmts:rootcimv2:Win32_Process")
 9 errReturn = objProcess.Create _
10     ("Notepad.exe", null, objConfig, intProcessID)

Creating a higher-priority process

Listing 14.12 contains a script that creates a higher-priority process. To carry out this task, the script must perform the following steps:

  1. Create a constant named ABOVE_NORMAL, and set the value to 32768. This is the value required to start a process with a priority of Above Normal.

  2. Create a variable to specify the computer name.

  3. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  4. Get an instance of the Win32_ProcessStartup class.

  5. Use the SpawnInstance_ method to create a new, “blank” instance of Win32_ProcessStartup. The new instance, which is used to store the startup properties of the process to be created, is named objConfig.

  6. Set the PriorityClass property of the new instance to ABOVE_NORMAL.

  7. Use a second GetObject call to get an instance of Win32_Process.

  8. Create the new process using the CreateProcess method.

    The first three parameters in the method specify the name of the executable file (Database.exe), the name of the startup folder (specifying Null gives the new process the same startup folder as the script that called the process), and the startup properties previously stored in objConfig.

    The fourth parameter (intProcessID) is a variable that represents the Process ID assigned to the new process. You can use this ID to monitor and, if necessary, terminate the process programmatically.

Example 14.12. Creating a Higher-Priority Process

1 Const ABOVE_NORMAL = 32768
2 strComputer = "."
3 Set objWMIService = GetObject("winmgmts:" _
4     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
5 Set objStartup = objWMIService.Get("Win32_ProcessStartup")
6 Set objConfig = objStartup.SpawnInstance_
7 objConfig.PriorityClass = ABOVE_NORMAL
8 Set objProcess = GetObject("winmgmts:rootcimv2:Win32_Process")
9 objProcess.Create "Database.exe", Null, objConfig, intProcessID

Terminating Processes

Computer problems are often due to a process that is no longer working as expected. For example, the process might be leaking memory, or it might have stopped responding to user input. When problems such as these occur, the process must be terminated. Although this might seem like a simple enough task, terminating a process can be complicated by several factors:

  • The process might be hung and therefore no longer responds to menu or keyboard commands for closing the application. This makes it all but impossible for the typical user to dismiss the application and terminate the process.

  • The process might be orphaned. For example, a script might create an instance of Word and then exit without destroying that instance. In effect, Word remains running on the computer, even though no user interface is visible. Because there is no user interface, there are no menu or keyboard commands available to terminate the process.

  • You might not know which process needs to be terminated. For example, you might want to terminate all programs that are exceeding a specified amount of memory.

  • Because Task Manager allows you to terminate only those processes that you created, you might not be able to terminate a process, even if you are an administrator on the computer.

Scripts enable you to overcome all of these potential obstacles, providing you with considerable administrative control over your computers. For example, if you suspect users are playing games that have been prohibited in your organization, you can easily write a script to connect to each computer, identify whether the game is running, and immediately terminate the process.

Scripting Steps

You can terminate a process by:

  • Terminating a process that is currently running. For example, you might need to terminate a diagnostic program running on a remote computer. If there is no way to control the application remotely, you can simply terminate the process for that application.

  • Preventing a process from running in the first place. By continuously monitoring process creation on a computer, you can identify and instantly terminate any process as soon as it starts. This provides one method of ensuring that certain applications (such as programs that download large media files over the Internet) are never run on certain computers.

Note

Note

Group Policy can also be used to restrict the programs that run on a computer. However, Group Policy can restrict only the programs run using either the Start menu or Windows Explorer; it has no effect on programs started using other means, such as the command line. By contrast, WMI can prevent a process from running regardless of how the process was started.

Terminating a process that is currently running

Listing 14.13 contains a script that terminates the process in which the application Diagnose.exe is currently running. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecQuery method to query the Win32_Process class.

    To restrict data retrieval to instances of Diagnose.exe, a WHERE clause is included that filters out all processes except those named Diagnose.exe.

  4. For each process in the collection, use the Terminate method to end the process.

Example 14.13. Terminating a Process

1 strComputer = "."
2 Set objWMIService = GetObject("winmgmts:" _
3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
4 Set colProcessList = objWMIService.ExecQuery _
5     ("SELECT * FROM Win32_Process WHERE Name = 'Diagnose.exe'")
6 For Each objProcess in colProcessList
7     objProcess.Terminate()
8 Next

Terminating a process as soon as it starts

Listing 14.14 contains a script that uses a temporary event consumer to terminate a process as soon as it starts. To carry out this task, the script must perform the following steps:

  1. Create a variable to specify the computer name.

  2. Use a GetObject call to connect to the WMI namespace rootcimv2 on the computer, and set the impersonation level to “impersonate.”

  3. Use the ExecNotificationQuery method to register for notification each time there is an instance creation (each time an instance is created within the namespace).

    To restrict data retrieval to the process named Download.exe, include a WHERE clause to filter out all instance creations that do not involve Download.exe.

  4. Create a loop that allows the script to run indefinitely.

    To stop monitoring, you need to either log off the computer or terminate the process in which the script runs.

  5. Use the NextEvent method to retrieve the properties of each event when it occurs.

  6. If Download.exe is created, use the Terminate method to terminate the new instance.

Example 14.14. Preventing a Process from Running

 1 strComputer = "."
 2 Set objWMIService = GetObject("winmgmts:" _
 3     & "{impersonationLevel=impersonate}!\" & strComputer & "
ootcimv2")
 4 Set colMonitoredProcesses = objWMIService. _
 5     ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent " _
 6         & " WITHIN 1 WHERE TargetInstance IS 'Win32_Process'")
 7 i = 0
 8 Do While i = 0
 9     Set objLatestProcess = colMonitoredProcesses.NextEvent
10     If objLatestProcess.TargetInstance.Name = "Download.exe" Then
11         objLatestProcess.TargetInstance.Terminate()
12     End If
13 Loop
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset