Fine-Tuning System Performance - Windows PowerShell for Administration: The Personal Trainer (2015)

Windows PowerShell for Administration: The Personal Trainer (2015)

Chapter 11. Fine-Tuning System Performance

An important part of every administrator’s job is to monitor network systems and ensure that everything is running smoothly—or as smoothly as can be expected, anyway. As you learned in the previous chapter, watching the event logs closely can help you detect and track problems with applications, security, and essential services. Often when you detect or suspect a problem, you’ll need to dig deeper to search out the cause of the problem and correct it. If you’re fortunate, by pinpointing the cause of a problem, you can prevent it from happening again.

Whenever the operating system or a user starts a service, runs an application, or executes a command, Windows starts one or more processes to handle the related program. Several commands are available to help you manage and monitor programs. These commands include the following:

· Debug-Process Debugs one or more processes running on the local computer.

Debug-Process [-Id] ProcessIDs | -InputObject Objects |
-Name Names

· Get-Process Lists all running processes by name and process ID. The list includes information on memory usage.

Get-Process -Id ProcessIDs | -InputObject Objects |
[[-Name] Names] [-ComputerName ComputerNames]
[-FileVersionInfo] [-Module]

· Start-Process Starts one or more processes on the local computer. To specify the program that runs in the process, enter the path to an executable file or script file. Alternatively, you can specify a file that can be opened in a program, such as a Microsoft Office Word document or Office Excel worksheet. If you specify a nonexecutable file, Start-Process starts the program that is associated with the file by using the default action. Typically, the default action is Open. You can set the action to take using the –Verb parameter.

Start-Process [-Verb {Edit|Open|Print|...}]
[-WorkingDirectory DirectoryPath] [[-ArgumentList] Args]
[-FilePath] PathToExeOrDoc [-Credential CredentialObject]
[-LoadUserProfile {$True|$False}] [-NoNewWindow] [-PassThru]
[-RedirectStandardError FilePath] [-RedirectStandardInput
FilePath] [-RedirectStandardOutput FilePath]
[-UseNewEnvironment] [-Wait] [-WindowStyle
{Normal|Hidden|Minimized|Maximized}]

· Stop-Process Stops running processes by name or process ID. Using filters, you can also halt processes by process status, session number, CPU time, memory usage, and more.

Stop-Process [-Id] ProcessIDs | -InputObject Objects |
-Name Names [-Force] [-PassThru]

· Wait-Process Waits for a specified process to be stopped before accepting more input.

Wait-Process -Id ProcessIDs | -InputObject Objects |
[-Name] Names [[-TimeOut] WaitTime]

In the sections that follow, you’ll find detailed discussions on how these commands are used. First, however, let’s look at the ways processes are run and the common problems you might encounter when working with them.

Understanding System and User Processes

When you want to examine processes that are running on a local or remote system, you can use Get-Process and other commands. With Get-Process, you can obtain the process ID, status, and other important information about processes running on a system. You also can use filters to include or exclude processes from Get-Process queries. To dig deeper, you can use the Win32_Process and Win32_Service classes.

Generally, processes that the operating system starts are referred to as system processes; processes that users start are referred to as user processes. Most user processes are run in interactive mode. That is, a user starts a process interactively with the keyboard or mouse. If the application or program is active and selected, the related interactive process has control over the keyboard and mouse until you switch control by terminating the program or selecting a different one. When a process has control, it’s said to be running “in the foreground.”

Processes can also run in the background, independently of user logon sessions. Background processes do not have control over the keyboard, mouse, or other input devices and are usually run by the operating system. Using the Task Scheduler, users can run processes in the background as well, however, and these processes can operate regardless of whether the user is logged on. For example, if Task Scheduler starts a scheduled job while the user is logged on, the process can continue even when the user logs off.

Windows tracks every process running on a system by image name, process ID, priority, and other parameters that record resource usage. The image name is the name of the executable that started the process, such as Msdtc.exe or Svchost.exe. The process ID is a numeric identifier for the process, such as 1160. The base priority is an indicator of how much of the system’s resources the process should get relative to other running processes. With priority processing, a process with a higher-priority gets preference over processes with lower priority, and the higher-priority process might not have to wait to get processing time, access memory, or work with the file system. A process with lower priority, on the other hand, usually must wait for a higher-priority process to complete its current task before gaining access to the CPU, memory, or the file system.

In a perfect world, processes would run perfectly and would never have problems. The reality is, however, that problems occur and they often appear when you least want them to. Common problems include the following:

· Processes become nonresponsive, such as when an application stops processing requests. When this happens, users might tell you that they can’t access a particular application, that their requests aren’t being handled, or that they were kicked out of the application.

· Processes fail to release the CPU, such as when you have a runaway process that is using up CPU time. When this happens, the system might appear to be slow or nonresponsive because the runaway process is hogging processor time and is not allowing other processes to complete their tasks.

· Processes use more memory than they should, such as when an application has a memory leak. When this happens, processes aren’t properly releasing memory that they’re using. As a result, the system’s available memory might gradually decrease over time and, as the available memory gets low, the system might be slow to respond to requests or it might become nonresponsive. Memory leaks can also make other programs running on the same system behave erratically.

In most cases, when you detect these or other problems with system processes, you’ll want to stop the process and start it again. You’ll also want to examine the event logs to see whether you can determine the cause of the problem. In the case of memory leaks, you'll want to report the memory leak to the developers and see whether an update that resolves the problem is available.

A periodic restart of an application with a known memory leak is often useful. Restarting the application should allow the operating system to recover any lost memory.

Examining Running Processes

To get a list of all processes running on a system, type get-process at the command prompt as shown in the following example and sample output:

get-process –computername fileserver86

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
56 7 2088 5868 59 0.09 3680 conhost
387 11 2148 1924 44 0.42 436 csrss
92 22 1804 528 39 0.22 496 csrss
217 12 1828 13480 55 3.31 2928 csrss
169 14 7000 5324 122 0.41 896 dwm
192 19 22220 36228 188 4.78 3040 dwm
1389 82 47260 51548 579 10.39 1540 explorer
0 0 0 4 0 0 Idle
357 28 26752 27464 302 0.39 812 LogonUI
915 26 4940 8084 38 1.92 588 lsass
523 54 110704 58340 299 139.34 1456 MsMpEng
255 11 5328 1996 50 6.39 2136 NisSrv
387 26 117412 123608 615 1.20 3700 powershell
218 10 2212 4792 81 0.73 1736 rdpclip
1005 52 22424 10576 320 1.25 1692 SearchIndexer
218 11 4248 4068 30 0.95 580 services
47 2 284 452 4 0.05 320 smss
458 62 41324 12420 324 2.02 3548 Snagit32
522 86 29832 22424 263 9.59 3864 SnagitEditor
81 9 1256 36 52 0.00 3732 SnagPriv
201 11 2620 1260 75 0.00 3992 splwow64
904 23 6092 7704 71 0.67 1068 spoolsv
602 19 6116 6692 47 0.81 660 svchost

Because the –ComputerName parameter accepts multiple name values, you can check the status of processes on multiple computers simply by typing the names of the computers to check in a comma-separate list as shown in the following example:

get-process –computername fileserver86, dcserver22, printserver31

Rather than type computer names each time, you can type computer names on separate lines in a text file and then get the list of computer names from the text file as shown in the following example:

get-process -computername (get-content c:\data\clist.txt)

Here, you get the list of remote computers to check from a file called Clist.txt in the C:\Data directory.

When you are looking for a specific process, you can reference the process by its process name or process ID. To match partial names, you can use wildcard characters as shown in the following example and sample output:

get-process win* –computername fileserver86

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
77 8 868 764 40 0.06 480 wininit
121 7 1336 912 52 0.02 540 winlogon
146 7 1248 10036 57 0.13 2956 winlogon
485 26 45992 69220 441 83.34 5200 WINWORD

Here, you look for all processes where the process name begins with win.

Get-Process returns objects representing each process matching the criteria you specify. As you can see from previous examples and sample output, the standard output includes:

· CPU An alias for TotalProcessorTime.TotalSeconds. This item shows the number of seconds of CPU time the process has used.

· Handles An alias for the HandleCount property. This item shows the number of file handles maintained by the process.

· NPM An alias for the NonpagedSystemMemorySize property. This item shows the amount of virtual memory for a process that cannot be written to disk.

· PM An alias for the PagedMemorySize property. This item shows the amount of committed virtual memory for a process that can be written to disk.

· VM An alias for the VirtualMemorySize property. This item shows the amount of virtual memory allocated to and reserved for a process.

· WS An alias for the WorkingSet property. This item shows the amount of memory the process is currently using, including both the private working set and the nonprivate working set.

· Id The process identification number.

· ProcessName The name of the process or executable running the process.

As you examine processes, keep in mind that a single application might start multiple processes. Generally, these processes are dependent on the central application process, and from this main process a process tree containing dependent processes is formed. When you terminate processes, you’ll usually want to target the main application process or the application itself rather than dependent processes. This approach ensures that the application is stopped cleanly.

To view all of the available properties, you need to format the output as a list, as shown in the following example and partial output:

get-process winword -computername server12 | format-list *

Name : WINWORD
Handles : 1118
VM : 768397312
WS : 148938752
PM : 195764224
NPM : 80304
Path : C:\Program Files (x86)\Microsoft Office\Office15\WINWORD.EXE
Company : Microsoft Corporation
CPU : 631.6948493
FileVersion : 15.0.4719.1000
ProductVersion : 15.0.4719.1000
Description : Microsoft Word
Product : Microsoft Office 2013
Id : 7308
PriorityClass : Normal
HandleCount : 1118
WorkingSet : 148938752
PagedMemorySize : 195764224
PrivateMemorySize : 195764224
VirtualMemorySize : 768397312
TotalProcessorTime : 00:10:31.6948493
BasePriority : 8
ExitCode :
HasExited : False
ExitTime :
Handle : 1216
MachineName : .
MainWindowHandle : 2755504
MainWindowTitle : Process.docx - Word
MainModule : System.Diagnostics.ProcessModule (WINWORD.EXE)
MaxWorkingSet : 1413120
MinWorkingSet : 204800
Modules : {System.Diagnostics.ProcessModule (WINWORD.EXE), System.Diagnostics.ProcessModule
(ntdll.dll), System.Diagnostics.ProcessModule (wow64.dll),
System.Diagnostics.ProcessModule (wow64win.dll)...}
NonpagedSystemMemorySize : 80304
NonpagedSystemMemorySize64 : 80304
PagedMemorySize64 : 195764224
PagedSystemMemorySize : 1123712
PagedSystemMemorySize64 : 1123712
PeakPagedMemorySize : 223801344
PeakPagedMemorySize64 : 223801344
PeakWorkingSet : 218066944
PeakWorkingSet64 : 218066944
PeakVirtualMemorySize : 794824704
PeakVirtualMemorySize64 : 794824704
PriorityBoostEnabled : True
PrivateMemorySize64 : 195764224
PrivilegedProcessorTime : 00:01:21.4481221
ProcessName : WINWORD
ProcessorAffinity : 4095
Responding : True
SessionId : 2
StartInfo : System.Diagnostics.ProcessStartInfo
StartTime : 6/8/2015 9:49:54 AM
SynchronizingObject :
Threads : {2016, 9144, 6996, 8852...}
UserProcessorTime : 00:09:10.2467272
VirtualMemorySize64 : 768397312
EnableRaisingEvents : False
StandardInput :
StandardOutput :
StandardError :
WorkingSet64 : 148938752
Site :
Container :

The output shows the exact configuration of the process. The properties you will work with the most are summarized in Table 11-1.

NOTE By default, many properties that measure memory usage are defined as 32-bit values. When working with Get-Process on 64-bit systems, you’ll find that these properties have both a 32-bit and a 64-bit version. On 64-bit systems, you’ll need to use the 64-bit versions to ensure you get accurate values.

TABLE 11-1 Properties of Get-Process and How They Are Used

PROPERTY NAME

PROPERTY DESCRIPTION

BasePriority

Shows the priority of the process. Priority determines how much of the system resources are allocated to a process. The standard priorities are Low (4), Below Normal (6), Normal (8), Above Normal (10), High (13), and Real-Time (24). Most processes have a Normal priority by default, and the highest priority is given to real-time processes.

CPU

Shows TotalProcessorTime in seconds.

Description

Shows a description of the process.

FileVersion

Shows the file version of the process’s executable.

HandleCount

Shows the number of file handles maintained by the process. The number of handles used is an indicator of how dependent the process is on the file system. Some processes have thousands of open file handles. Each file handle requires system memory to maintain.

Id

Shows the run-time identification number of the process.

MinWorkingSet

Shows the minimum amount of working set memory used by the process.

Modules

Shows the executables and dynamically linked libraries used by the process.

NonpagedSystemMemorySize/NonpagedSystemMemorySize64

Shows the amount of virtual memory for a process that cannot be written to disk. The nonpaged pool is an area of RAM for objects that can’t be written to disk. You should note processes that require a high amount of nonpaged pool memory. If the server doesn’t have enough free memory, these processes might be the reason for a high level of page faults.

PagedSystemMemorySize/PagedSystemMemorySize64

Shows the amount of committed virtual memory for a process that can be written to disk. The paged pool is an area of RAM for objects that can be written to disk when they aren’t used. As process activity increases, so does the amount of pool memory the process uses. Most processes have more paged pool than nonpaged pool requirements.

Path

Shows the full path to the executable for the process.

PeakPagedMemorySize/
PeakPagedMemorySize64

Shows the peak amount of paged memory used by the process.

PeakVirtualMemorySize/
PeakVirtualMemorySize64

Shows the peak amount of virtual memory used by the process.

PeakWorkingSet/
PeakWorkingSet64

Shows the maximum amount of memory the process used, including both the private working set and the nonprivate working set. If peak memory is exceptionally large, this can be an indicator of a memory leak.

PriorityBoostEnabled

Shows a Boolean value that indicates whether the process has the PriorityBoost feature enabled.

PriorityClass

Shows the priority class of the process.

PrivilegedProcessorTime

Shows the amount of kernel-mode usage time for the process.

ProcessName

Shows the name of the process.

ProcessorAffinity

Shows the processor affinity setting for the process.

Responding

Shows a Boolean value that indicates whether the process responded when tested.

SessionId

Shows the identification number user (session) within which the process is running. This corresponds to the ID value listed on the Users tab in Task Manager.

StartTime

Shows the date and time the process was started.

Threads

Shows the number of threads that the process is using. Most server applications are multithreaded, which allows concurrent execution of process requests. Some applications can dynamically control the number of concurrently executing threads to improve application performance. Too many threads, however, can actually reduce performance, because the operating system has to switch thread contexts too frequently.

TotalProcessorTime

Shows the total amount of CPU time used by the process since it was started. If a process is using a lot of CPU time, the related application might have a configuration problem. This can also indicate a runaway or nonresponsive process that is unnecessarily tying up the CPU.

UserProcessorTime

Shows the amount of user-mode usage time for the process.

VirtualMemorySize/
VirtualMemorySize64

Shows the amount of virtual memory allocated to and reserved for a process. Virtual memory is memory on disk and is slower to access than pooled memory. By configuring an application to use more physical RAM, you might be able to increase performance. To do this, however, the system must have available RAM. If it doesn’t, other processes running on the system might slow down.

WorkingSet/WorkingSet64

Shows the amount of memory the process is currently using, including both the private working set and the nonprivate working set. The private working set is memory the process is using that cannot be shared with other processes. The nonprivate working set is memory the process is using that can be shared with other processes. If memory usage for a process slowly grows over time and doesn’t go back to the baseline value, this can be an indicator of a memory leak.

Filtering Process Output

By redirecting the output to Where-Object, you can filter Get-Process using any of the properties available. This means you can specify that you want to see only processes that aren’t responding or only processes that use a large amount of CPU time.

You designate how a filter should be applied using filter operators. The available filter operators include:

· –Eq Equals. If the property contains the specified value, the process is included in the output.

· –Ne Not equals. If the property contains the specified value, the process is excluded from the output.

· –Gt Greater than. If the property contains a numeric value and that value is greater than the value specified, the process is included in the output.

· –Lt Less than. If the property contains a numeric value and that value is less than the value specified, the process is included in the output.

· –Ge Greater than or equal to. If the property contains a numeric value and that value is greater than or equal to the value specified, the process is included in the output.

· –Le Less than or equal to. If the property contains a numeric value and that value is less than or equal to the value specified, the process is included in the output.

· –Match Pattern match. If the property contains a match for this string, the process is included in the output.

As Table 11-2 shows, the values that you can use with filter operators depend on the Get-Process property you use. Remember that all properties are available even if they aren’t normally displayed with the parameters you’ve specified.

TABLE 11-2 Filter Operators and Valid Values for Get-Process

PROPERTY NAME

OPERATORS TO USE

VALID VALUES

BasePriority

–eq, –ne, –gt, –lt, –ge, –le

Any value from 0 to 24

HandleCount

–eq, –ne, –gt, –lt, –ge, –le

Any valid positive integer

MachineName

–eq, –ne

Any valid string of characters

Modules

–eq, –ne, –match

Dynamic-link library (DLL) name

PrivilegedProcessorTime

–eq, –ne, –gt, –lt, –ge, –le

Any valid time in the format hh:mm:ss

ProcessID

–eq, –ne, –gt, –lt, –ge, –le

Any valid positive integer

ProcessName

–eq, –ne

Any valid string of characters

Responding

–eq, –ne

$True, $False

SessionID

–eq, –ne, –gt, –lt, –ge, –le

Any valid session number

Username

–eq, –ne

Any valid user name, with user name only or in domain\user format

UserProcessorTime

–eq, –ne, –gt, –lt, –ge, –le

Any valid time in the format hh:mm:ss

WorkingSet

–eq, –ne, –gt, –lt, –ge, –le

Any valid integer, expressed in kilobytes (KB)

By default, Get-Process looks at all processes regardless of their status. With the Responding property, you can find processes that either are or aren’t responding. This property is set to a Boolean value. Consider the following examples:

get-process | where-object {$_.responding -eq $False}
get-process | where-object {$_.responding -eq $True}

In the first example, you list all processes that aren’t responding. In the second example, you list all processes that are responding.

Because high-priority processes use more processor time than other processes, you might want to review the high-priority processes running on a computer when you are evaluating performance. Most processes have a normal priority and a priority value of 8. You can find processes with a priority higher than 8 as shown in the following example and sample output:

get-process | where-object {$_.basepriority -gt 8}

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
209 12 1712 3712 48 0.16 400 csrss
87 11 1280 3452 43 0.42 464 csrss
162 14 1876 34108 197 0.67 1636 csrss
177 15 21800 33568 102 0.09 896 dwm
198 21 14320 62948 157 1.39 2852 dwm
322 22 16952 29480 240 0.28 888 LogonUI
1749 306 55964 62696 1421 10.70 604 lsass
279 11 4832 8656 34 2.59 596 services
55 2 272 1052 4 0.03 296 smss
84 8 812 3704 42 0.08 472 wininit
125 7 1396 5716 56 0.05 500 winlogon
153 7 1252 5276 51 0.11 2328 winlogon

You also might want to find processes that are using a lot of CPU time. In the following example and sample output, you check for processes that are using more than 30 minutes of privileged processor time:

get-process | where-object {$_.privilegedprocessortime -gt "00:30:00"}

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
553 32 52924 80096 487 3026.42 5200 W3SVC

Viewing the Relationship Between Running Processes and Services

When you use Win32_Service with Get-Process, you can examine the relationship between services configured on a computer and running processes. The ID of the process under which a service is running is shown as part of the standard output when you work with Win32_Service. Here is an example and sample output for the DFS service:

get-wmiobject -class win32_service -filter "name='dfs'"

ExitCode : 0
Name : Dfs
ProcessId : 1772
StartMode : Auto
State : Running
Status : OK

Using the ProcessId property of the Win32_Service object, you can view detailed information about the process under which a service is running, as shown in the following example:

$s = get-wmiobject -class win32_service -filter "name='dfs'"
get-process -id $s.processid

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

127 11 1888 5312 33 0.03 1772 dfssvc

Alternatively, you can get the same result using the following code:

get-wmiobject -class win32_service -filter "name='dfs'" |
foreach ($a) {get-process -id $_.processid}

By default, the output of Get-Process is formatted as a table, but you can also format the output as a list. Beyond formatting, the important thing to note here is that Get-Process lists services by the base name of the executable that starts the service.

You can use the correlation between processes and services to help you manage systems. For example, if you think you are having problems with the World Wide Web Publishing Service (W3svc), one step in your troubleshooting process is to begin monitoring the service’s related process or processes. You would want to track the following:

· Process status, such as whether the process is responding or not responding

· Memory usage, including the working set, paged system memory, and virtual memory

· CPU time, including privileged processor time and user processor time

By tracking these statistics over time, you can watch for changes that can indicate the process has stopped responding, the process is a runaway process hogging CPU time, or there is a memory leak.

Viewing Lists of DLLs Being Used by Processes

When you use Get-Process, you can examine the relationship between running processes and DLLs configured on the system. In the output, the names of DLLs that the process uses are stored in the Modules property. However, the standard output might not show you the complete list. Consider the following example and sample output:

get-process dwm | format-list modules

Modules : {System.Diagnostics.ProcessModule (dwm.exe),
System.Diagnostics.ProcessModule (ntdll.dll),
System.Diagnostics.ProcessModule (KERNEL32.DLL),
System.Diagnostics.ProcessModule (KERNELBASE.dll)...}

Modules : {System.Diagnostics.ProcessModule (dwm.exe),
System.Diagnostics.ProcessModule (ntdll.dll),
System.Diagnostics.ProcessModule (KERNEL32.DLL),
System.Diagnostics.ProcessModule (KERNELBASE.dll)...}

TIP The preference variable $FormatEnumerationLimit controls how many enumerated items are included in a grouped display. The default value is 4, and this is why only four DLLs are shown here. If you increment this variable, you’ll be able to see more values by default. In this example, you would have needed to set this variable to 30 or more to see all the DLLs.

Here, per the default configuration of Windows PowerShell, you see only four values for the Modules property, and the rest of the values are truncated. To see all the DLLs, store the Process object in a variable and then list the value of the Modules property as shown in the following example and sample output:

$p = get-process dwm
$p.modules

Size(K) ModuleName FileName
------- ---------- --------
140 dwm.exe C:\Windows\system32\dwm.exe
1712 ntdll.dll C:\Windows\SYSTEM32\ntdll.dll
1272 KERNEL32.DLL C:\Windows\system32\KERNEL32.DLL
1108 KERNELBASE.dll C:\Windows\system32\KERNELBASE.dll
568 apphelp.dll C:\Windows\system32\apphelp.dll
680 msvcrt.dll C:\Windows\system32\msvcrt.dll
1500 USER32.dll C:\Windows\system32\USER32.dll
1348 GDI32.dll C:\Windows\system32\GDI32.dll
216 IMM32.dll C:\Windows\system32\IMM32.dll
. . .
280 powrprof.dll C:\Windows\SYSTEM32\powrprof.dll

Alternatively, you can get the same result using the following code:

get-process dwm | foreach ($a) {$_.modules}

Knowing which DLL modules a process has loaded can further help you pinpoint what might be causing a process to become nonresponsive, to fail to release the CPU, or to use more memory than it should. In some cases, you might want to check DLL versions to ensure that they are the correct DLLs that the system should be running. To do this, you need to consult the Microsoft Knowledge Base or manufacturer documentation to verify DLL versions and other information.

If you are looking for processes using a specified DLL, you can also specify the name of the DLL you are looking for. For example, if you suspect that the printer spooler driver Winspool.drv is causing processes to hang up, you can search for processes that use Winspool.drv instead of Winspool32.drv and check their status and resource usage.

The syntax that you use to specify the DLL to find is

get-process | where-object {$_.modules -match "DLLName"}

where DLLName is the name of the DLL to search for. Get-Process matches the DLL name without regard to the letter case, and you can enter the DLL name in any letter case. In the following example, you are looking for processes using Winspool.drv, and the output shows the processes using the DLL, along with their basic process information:

get-process | where-object {$_.modules -match "winspool.drv"}

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
1063 55 29152 77720 439 2.28 3228 explorer
217 10 1804 7208 85 0.20 3116 rdpclip
467 23 4724 11840 91 0.33 1372 spoolsv
367 28 9236 13056 860 11.23 2320 svchost

Stopping Processes

When you want to stop processes that are running on a local or remote system, you can use Stop-Process. With Stop-Process, you can stop processes by process ID using the –Id parameter or by name using the –Name parameter. Although you cannot use wildcards with the –Id parameter, you can use wildcards with the –Name parameter.

By default, Stop-Process prompts for confirmation before stopping any process that is not owned by the current user. If you have appropriate permissions to stop a process and don’t want to be prompted, use the –Force parameter to disable prompting.

If you want to stop multiple processes by process ID or name, you can enter multiple IDs or names as well. With process names, however, watch out, because Stop-Process stops all processes that have that process name. Thus, if three instances of Svchost are running, all three processes are stopped if you use Stop-Process with that image name.

REAL WORLD As you examine processes, keep in mind that a single application might start multiple processes. Generally, you will want to stop the parent process, which should stop the entire process tree, starting with the parent application process and including any dependent processes.

Consider the following examples to see how you can use Stop-Process:

Stop process ID 1106:

stop-process 1106

Stop all processes with the name W3Svc:

stop-process –name w3svc

Stop processes 1106, 1241, and 1546:

stop-process 1106, 1241, 1546

Force process 891 to stop:

stop-process -force –id 891

To ensure that only processes matching specific criteria are stopped, you can use Get-Process and Stop-Process together. For example, you might want to use Get-Process to get only instances of Winword that are not responding and should be stopped, rather than all instances of Winword (which is the default when you use the –Name parameter). Or you might want to get and stop all processes using a specific DLL.

When you are stopping processes, you want to be careful not to accidentally stop critical system processes, such as Lsass, Wininit, or Winlogon. Typically, system processes have a process ID with a value less than 1000. One safeguard you can use when stopping processes is to ensure the process ID is greater than 999.

Consider the following examples to see how you can use Get-Process with Stop-Process:

Stop instances of Winword that are not responding:

get-process –name winword | where-object {$_.responding
-eq $False} | stop-process

Stop all processes with a process ID greater than 999 if they aren’t responding:

get-process | where-object {$_.id -gt 999} | where-object
{$_.responding -eq $False} | stop-process

Stop all processes using the Winspool.drv DLL:

get-process | where-object {$_.modules -match "winspool.drv"} |
stop-process

Although Stop-Process doesn’t support the –ComputerName parameter, you can use the following technique to manage the processes on remote computers:

get-process w3svc -computername engpc18 | stop-process

invoke-command -computername engpc18 -scriptblock { get-process w3svc | stop-process }

Here, you use Get-Process to get a Process object on a remote computer, and then you stop the process by using Stop-Process. Note that this command reports only failure. It won’t confirm that a process was stopped, but it will tell you that the process was not found or could not be stopped.

Digging Deeper into Processes

In addition to using Get-Process to get information about running processes, you can use Get-WmiObject and the Win32_Process class. If you type get-wmiobject -class win32_process, you’ll see detailed information on every process running on the computer. To examine a specific process, you can filter by image name. As shown in the following example and sample output, the image name is the name of the executable for the process:

get-wmiobject -class win32_process -filter "name='msdtc.exe'"

Caption : msdtc.exe
CommandLine : C:\Windows\System32\msdtc.exe
CreationClassName : Win32_Process
CreationDate : 20150608090830.314896-420
CSCreationClassName : Win32_ComputerSystem
CSName : CORPSERVER64
Description : msdtc.exe
ExecutablePath : C:\Windows\System32\msdtc.exe
ExecutionState :
Handle : 2552
HandleCount : 167
InstallDate :
KernelModeTime : 312500
MaximumWorkingSetSize : 1380
MinimumWorkingSetSize : 200
Name : msdtc.exe
OSCreationClassName : Win32_OperatingSystem
OSName : Microsoft Windows Server 2012 R2
Datacenter|C:\Windows|\Device\Harddisk0\Partition2
OtherOperationCount : 159
OtherTransferCount : 306
PageFaults : 2250
PageFileUsage : 2228
ParentProcessId : 596
PeakPageFileUsage : 2724
PeakVirtualSize : 2199068520448
PeakWorkingSetSize : 7508
Priority : 8
PrivatePageCount : 2281472
ProcessId : 2552
QuotaNonPagedPoolUsage : 13
QuotaPagedPoolUsage : 76
QuotaPeakNonPagedPoolUsage : 13
QuotaPeakPagedPoolUsage : 76
ReadOperationCount : 0
ReadTransferCount : 0
SessionId : 0
Status :
TerminationDate :
ThreadCount : 9
UserModeTime : 0
VirtualSize : 2199067389952
WindowsVersion : 6.3.9600
WorkingSetSize : 7081984
WriteOperationCount : 2
WriteTransferCount : 102400
PSComputerName : CORPSERVER64
ProcessName : msdtc.exe
Handles : 167
VM : 2199067389952
WS : 7081984
Path : C:\Windows\System32\msdtc.exe

Win32_Process objects provide some information that Process objects don’t, including details on read and write operations. The rest of the information is the same as that provided by Get-Process, albeit in some cases the information is presented in a different way.

Process objects have a StartTime property, and Win32_Process objects have a CreationDate property. Whereas the StartTime property is presented in datetime format, the CreationDate property is presented as a datetime string. Using the StartTime property, you can search for all processes that have been running for longer than a specified period of time. In the following example, you look for processes that have been running longer than one day:

$yesterday = (get-date).adddays(-1)
get-process | where-object {$_.starttime -gt $yesterday}

Alternatively, you can get the same result using the following code:

get-process | where-object {$_.starttime –gt
(get-date).adddays(-1)}

With the CreationDate property, you can perform the same search. Here is an example:

$yesterday = (get-date).adddays(-1)

get-wmiobject -class win32_process | where-object
{$_.creationdate –gt $yesterday}

Win32_Process objects have a property called threadcount, which is a count of threads associated with a process. You can list the thread count as shown in the following example:

get-wmiobject -class win32_process -filter "name='msdtc.exe'" |
format-list name, threadcount

name : msdtc.exe
threadcount : 9

Process objects have a Threads property that contains all the threads associated with a process. You can count the threads as shown in the following example:

$p = get-process –name msdtc
write-host "Number of threads: " ($p.threads).count

Number of threads: 9

You can view and work with each individual Thread object as well. As shown in the following example and sample output, you can list the information associated with each Thread object:

$p = get-process –name msdtc
$p.threads

BasePriority : 8
CurrentPriority : 14
Id : 1356
IdealProcessor :
PriorityBoostEnabled : True
PriorityLevel : Normal
PrivilegedProcessorTime : 00:00:00.0156250
StartAddress : 140736834851856
StartTime : 6/8/2015 9:08:30 AM
ThreadState : Wait
TotalProcessorTime : 00:00:00.0156250
UserProcessorTime : 00:00:00
WaitReason : UserRequest
ProcessorAffinity :
Site :
Container :

BasePriority : 8
CurrentPriority : 10
. . .

Or you can view details for a specific thread by referencing its index position in the Threads object array. For example, if you want to view the first Thread object, you can reference $p.threads[0].

Each thread has a base priority, a current priority, an ID, a start address, and a thread state. If the thread is waiting for another process or thread, the wait reason is also listed. Wait reasons include Executive (when the thread is waiting on the operating system kernel components) and UserRequest (when the thread is waiting on user-mode components).

When you are working with Win32_Process objects, you can use several methods to work with processes. These methods include the following:

· GetOwner() Gets the user account under which the process is running

· GetOwnerSid() Gets the security identifier of the user account under which the process is running

· Terminate() Stops a process that is running on a local or remote system

The basic syntaxes for getting the process owner and the owner’s security identifier are

$processObject.GetOwner()

and

$processObject.GetOwnerSid()

where $processObject is a reference to a Win32_Process object. Here is an example and partial output:

$p = get-wmiobject -class win32_process -filter "name='notepad.exe'"
$p.getowner()

Domain : IMAGINEDLANDS
ReturnValue : 0
User : WILLIAMS

Here, you examine a running instance of Notepad and get the owner of the Notepad process. In the return value, note the Domain and User properties, which show the domain and user account of the process owner, respectively. As shown in the following example and partial output, you can display the security identifier of the process owner by typing

$p.getownersid()

Sid : S-1-5-21-4857584848-3848484848-8484884848-1111

In the return value, the Sid property contains the owner’s security identifier.

As shown in the following example and partial output, you can stop the process by typing the following:

$p.terminate()

ReturnValue : 0

The return value in the output is what you want to focus on. A return value of 0 indicates success. Any other return value indicates an error. Typically, errors occur because you aren’t the process owner and don’t have appropriate permissions to terminate the process. You can resolve this problem by providing credentials or by using an elevated administrator PowerShell prompt.

You can use the techniques discussed previously to work with processes when Get-WmiObject returns a single matching Win32_Process object. However, these techniques won’t work as expected when Get-WmiObject returns multiple Win32_Process objects. The reason for this is that the objects are stored in an array and you must specify the instance within the array to work with. One technique for doing so is shown in the following example and partial output:

$procs = get-wmiobject -class win32_process -filter "name='notepad.exe'"
foreach ($p in $procs) { $p.getowner() }

Domain : IMAGINEDLANDS
ReturnValue : 0
User : WILLIAMS

Domain : IMAGINEDLANDS
ReturnValue : 0
User : WILLIAMS

Here, two instances of Notepad are running, and you list the owner of each process. This technique works when there is only one instance of Notepad running as well.