Hey, Scripting Guy! How Can I Identify and Delete an Instance of a Process?


Hey, Scripting Guy! Question


Hey, Scripting Guy! I want to do a query for a process, and if the process is running, I want to delete that process. I know I could write a script by using WMI, but is there something native to Windows PowerShell that I can use to find and to delete the process? Next question: what if there is more than one process I have to delete? Can I find those processes and delete them? I remain your humble youngling.

- RB

SpacerHey, Scripting Guy! Answer

Hi RB,


Yes, the force is strong with this one. We can sense it by the calm aura that pervades the manner of one who possesses such strength. Such power does not have to be flashy, as is exhibited by this creature:

Image of a shark off Little Cayman

 


Windows PowerShell is not flashy, but do not mistake it for a mere replacement for the command prompt. The real power of Windows PowerShell is in the way that we can use one command to feed into another command. Mastering the pipeline unlocks the key to excellent capabilities (kind of like mastering the lightsaber is essential for younglings).







This week we will be looking at the basics of Windows PowerShell. Windows PowerShell is installed by default on Windows 7 and Windows Server 2008 R2. It is an optional installation on Windows Server 2008 and a download for Windows Vista, Windows XP, and Windows Server 2003. The Windows PowerShell Scripting Hub is a good place to get started with Windows PowerShell.



We are not sure that telling you to close your eyes and feel the pipeline would do much good. Neither would exhortations to become one with the pipeline. Therefore, we will provide some examples to show by using the Windows PowerShell pipeline. If we want to obtain information about the Notepad process (assuming that Notepad is actually running), we use the Get-Process cmdlet:

Get-Process Notepad

We do not have to specify the –name parameter if we do not want to do this, because the –name parameter is the default parameter with Get-Process. We can type the –name parameter and get information about the Notepad process. This is seen here:

PS C:\> Get-Process -name notepad

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
47 2 976 3512 59 0.10 3960 notepad


To stop the Notepad process, we use the Stop-Process cmdlet. If, however, we are not used to using the –name parameter with the Get-Process, cmdlet we will receive a shock when we try the same syntax with Stop-Process:

PS C:\> Stop-Process notepad
Stop-Process : Cannot bind parameter 'Id'. Cannot convert value "notepad" to ty
pe "System.Int32". Error: "Input string was not in a correct format."
At line:1 char:13
+ Stop-Process <<<< notepad
+ CategoryInfo : InvalidArgument: (:) [Stop-Process], ParameterBi
ndingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerSh
ell.Commands.StopProcessCommand

The reason for the error is that the –name parameter occupies the first position for the Get-Process cmdlet, and the –id parameter is the first position parameter for the Stop-Process cmdlet. When we did not use any named parameters, the Stop-Process cmdlet looked for a process with the process ID of "notepad" which is not an integer, and this caused the error. The –name parameter is a named parameter in the Stop-Process cmdlet. This means if we want to use the name of a process to stop, we must specify the –name parameter. This is seen here:

Stop-Process -name notepad

To avoid these kinds of errors, you can always use parameters (which is a best practice when you write scripts), or you can use the pipeline. The advantage of using the pipeline is that you do not have to worry about all the parameters. You can use Windows PowerShell to find the process that you are interested in, and pipeline the results of the first command to the second command that will stop the process. This is seen here:

Get-Process notepad | Stop-Process

A session that starts an instance of Notepad, identifies the Notepad process, and then deletes that process is seen here:

Image of a Notepad process being started, identified, and deleted

 


You can use wildcard characters to identify processes. This technique can be both dangerous and useful. Here is an example of using wildcard characters to simplify finding all the Notepad processes:

PS C:\> Get-Process note*

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
47 2 976 3464 59 0.05 2056 notepad
47 2 976 3488 59 0.09 3292 notepad


You can then pipeline the result to the Stop-Process cmdlet and stop all instances of the Notepad process that are running on the computer:

Get-Process note* | Stop-Process

An example of working with processes by using wildcard characters is seen here:

Image of working with processes by using wildcard characters

 


Using wildcard characters can be dangerous if you are not careful. An example of such a dangerous command is seen here where we get a list of all the processes that are running on the computer, and pipeline them to the Stop-Process cmdlet. This will stop every process that is running on the computer, which for most operating systems will cause the computer to shut down (on Windows Vista and later, this command would have to be run with administrative rights).

Get-Process * | Stop-Process

Of course, if you want to shutdown the operating system it is best to use the shutdown method from the Win32_OperatingSystem WMI class.


Suppose we have several instances of Notepad that are running. One instance has been running for a while and has consumed more CPU time than the other process. We can get this information as seen here:

PS C:\> Get-Process notepad

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
47 2 976 3452 59 0.10 2688 notepad
49 2 1160 3936 60 1.13 3984 notepad


Whereas we could definitely use the process ID—3984 in this example—to stop the process that is using the most CPU time, we may not want to type two separate commands (or perhaps we want to automate the task of stopping a process that is using too much CPU time). To do this, we pipeline the results of the first query to the Where-Object cmdlet. We can use the alias for Where-Object, which is just Where. The alias eliminates some typing that is required for this command without sacrificing any readability. If we were not worrying about readability, we could use gps as an alias for the Get-Process cmdlet, and we could use ? as the alias for the Where-Object. The short command is shown the Where-Object. The short command is shown here:


PS C:\> gps notepad | ? { $_.cpu -gt 1 }

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
47 2 1316 4080 60 1.38 2420 notepad


The way I generally type the command is to spell out Get-Process (I use tab completion to spell it out: I only have to type Get-p and then I press the TAB key.) The Where-Object cmdlet is used to filter the process objects as they come across the pipeline. Each instance of a process with the name of Notepad is returned by the Get-Process cmdlet. As the process comes across the pipeline, the $_ automatic variable represents the current process object on the pipeline. This enables us to examine the properties of the process object. We inspect the amount of CPU time that is being used by the process to see whether it exceeds 1. If it does, the filter will enable the process object to continue. In the example seen here we display basic information about the process on the console:

PS C:\> Get-Process notepad | Where { $_.cpu -gt 1 }

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
49 2 1160 3936 60 1.13 3984 notepad


If we are not sure which properties are available for us to use in the Where-Object filter, we can use the Get-Member cmdlet. If we select the properties, we will eliminate the methods. This command is seen here:

PS C:\> Get-Process | Get-Member -MemberType property

However, we will also miss the instances of ScriptProperty and AliasProperty. To make sure we can find the other properties that were added by the Windows PowerShell team, we use a wildcard character in front of the MemberType property. The CPU property is one that was added by the Windows PowerShell team. It is a ScriptProperty. This is seen This is seen here:

PS C:\> Get-Process | Get-Member -MemberType *property

TypeName: System.Diagnostics.Process

Name MemberType Definition
---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
PM AliasProperty PM = PagedMemorySize
VM AliasProperty VM = VirtualMemorySize
WS AliasProperty WS = WorkingSet
__NounName NoteProperty System.String __NounName=Process
BasePriority Property System.Int32 BasePriority {get;}
Container Property System.ComponentModel.IContainer C...
EnableRaisingEvents Property System.Boolean EnableRaisingEvents...
ExitCode Property System.Int32 ExitCode {get;}
ExitTime Property System.DateTime ExitTime {get;}
Handle Property System.IntPtr Handle {get;}
HandleCount Property System.Int32 HandleCount {get;}
HasExited Property System.Boolean HasExited {get;}
Id Property System.Int32 Id {get;}
MachineName Property System.String MachineName {get;}
MainModule Property System.Diagnostics.ProcessModule M...
MainWindowHandle Property System.IntPtr MainWindowHandle {get;}
MainWindowTitle Property System.String MainWindowTitle {get;}
MaxWorkingSet Property System.IntPtr MaxWorkingSet {get;s...
MinWorkingSet Property System.IntPtr MinWorkingSet {get;s...
Modules Property System.Diagnostics.ProcessModuleCo...
NonpagedSystemMemorySize Property System.Int32 NonpagedSystemMemoryS...
NonpagedSystemMemorySize64 Property System.Int64 NonpagedSystemMemoryS...
PagedMemorySize Property System.Int32 PagedMemorySize {get;}
PagedMemorySize64 Property System.Int64 PagedMemorySize64 {get;}
PagedSystemMemorySize Property System.Int32 PagedSystemMemorySize...
PagedSystemMemorySize64 Property System.Int64 PagedSystemMemorySize...
PeakPagedMemorySize Property System.Int32 PeakPagedMemorySize {...
PeakPagedMemorySize64 Property System.Int64 PeakPagedMemorySize64...
PeakVirtualMemorySize Property System.Int32 PeakVirtualMemorySize...
PeakVirtualMemorySize64 Property System.Int64 PeakVirtualMemorySize...
PeakWorkingSet Property System.Int32 PeakWorkingSet {get;}
PeakWorkingSet64 Property System.Int64 PeakWorkingSet64 {get;}
PriorityBoostEnabled Property System.Boolean PriorityBoostEnable...
PriorityClass Property System.Diagnostics.ProcessPriority...
PrivateMemorySize Property System.Int32 PrivateMemorySize {get;}
PrivateMemorySize64 Property System.Int64 PrivateMemorySize64 {...
PrivilegedProcessorTime Property System.TimeSpan PrivilegedProcesso...
ProcessName Property System.String ProcessName {get;}
ProcessorAffinity Property System.IntPtr ProcessorAffinity {g...
Responding Property System.Boolean Responding {get;}
SessionId Property System.Int32 SessionId {get;}
Site Property System.ComponentModel.ISite Site {...
StandardError Property System.IO.StreamReader StandardErr...
StandardInput Property System.IO.StreamWriter StandardInp...
StandardOutput Property System.IO.StreamReader StandardOut...
StartInfo Property System.Diagnostics.ProcessStartInf...
StartTime Property System.DateTime StartTime {get;}
SynchronizingObject Property System.ComponentModel.ISynchronize...
Threads Property System.Diagnostics.ProcessThreadCo...
TotalProcessorTime Property System.TimeSpan TotalProcessorTime...
UserProcessorTime Property System.TimeSpan UserProcessorTime ...
VirtualMemorySize Property System.Int32 VirtualMemorySize {get;}
VirtualMemorySize64 Property System.Int64 VirtualMemorySize64 {...
WorkingSet Property System.Int32 WorkingSet {get;}
WorkingSet64 Property System.Int64 WorkingSet64 {get;}
Company ScriptProperty System.Object Company {get=$this.M...
CPU ScriptProperty System.Object CPU {get=$this.Total...
Description ScriptProperty System.Object Description {get=$th...
FileVersion ScriptProperty System.Object FileVersion {get=$th...
Path ScriptProperty System.Object Path {get=$this.Main...
Product ScriptProperty System.Object Product {get=$this.M...
ProductVersion ScriptProperty System.Object ProductVersion {get=...


As soon as we have the filter working correctly and we see that it is returning the results that we are interested in obtaining, we can just pipeline the resulting process object to the Stop-Process cmdlet. This is shown here:

PS C:\> Get-Process notepad | Where { $_.cpu -gt 1 } | Stop-Process

The ability to add pipelines together, by feeding the results of one pipeline into another pipeline as shown earlier, is where we obtain the real power of Windows PowerShell. It is a new concept for people who have a Windows background, but is something that people have done for years in other consoles. The big difference is that we pass objects through the pipeline, and not merely text. Join us tomorrow as we continue our Windows PowerShell Basics Week. Until then, peace.


 


Ed Wilson and Craig Liebendorfer, Scripting Guys

Comments (0)

Skip to main content