Summary: Microsoft Scripting Guy Ed Wilson shows four ways to kill a process by using Windows PowerShell and WMI.
Hey, Scripting Guy! I have been playing around with your scripts that explore WMI methods and WMI writable properties, but I am having problems calling the WMI methods. Can you help me?
—ET
Hello ET,
Microsoft Scripting Guy, Ed Wilson, is here. The Scripting Wife and I are super excited! Tomorrow night (August 9, 2011) we are going to appear at the Corpus Christi PowerShell User Group in Corpus Christi, Texas. This is their first meeting, and we hope to get them started out right. The group president, Mark Adam Carter, has been really busy getting everything set up for this meeting. If you are in the neighborhood, plan on stopping by. It will be a great meeting!
I wrote that series of articles you refer to as leadup to the 2011 Scripting Games. The series itself consisted of four articles:
- Use PowerShell to Find WMI Classes That Contain Methods
- Use PowerShell to Find Writable WMI Properties
- Explore WMI Methods and Properties Via PowerShell Script
- Get All Methods and Writable Properties from All WMI Classes
ET, phone home. Just kidding. ET, the listing of all methods and writable properties from all WMI classes is a very good place to start, if you are looking to call some WMI methods. One reason for this is that the available classes varies from version to version of the operating system. In addition, the available classes will vary depending on which options are installed. The other thing to keep in mind is that some classes have added additional methods to classes in later versions of the operating system. Examples of this are the Enable and Disable methods that are available in the Win32_NetworkAdapter WMI class. These methods were added to Windows Vista. I wrote about these methods in How Can I Enable or Disable My Network Adapter? blog post.
There are actually several ways to call WMI methods in Windows PowerShell. One reason for this is that some WMI methods are instance methods, which means they only work on an instance of the class. Other methods are static methods, which means they do not operate on an instance of the class. For example, the Terminate method from the Win32_Process class is an instance method—it will operate only against a specific instance of the Win32_Process. If I do not have a reference to a process, I cannot terminate the process. On the other hand, if I want to create a new instance of a Win32_Process class, I do not grab a reference to an instance of the class. For example, I do not grab an instance of Calculator to create an instance of Notepad. Therefore, I need a static method that is always available.
ET, let me illustrate the first of these two principles—instance methods and static methods—with a short example (I will talk about static methods tomorrow). First, I create an instance of Notepad. I then use the Get-Process cmdlet to view the process (gps is an alias for the Get-Process cmdlet). This is shown here:
PS C:\> notepad
PS C:\> Get-WmiObject win32_process -Filter "name = 'notepad.exe'"
__GENUS : 2
__CLASS : Win32_Process
__SUPERCLASS : CIM_Process
__DYNASTY : CIM_ManagedSystemElement
__RELPATH : Win32_Process.Handle="588"
__PROPERTY_COUNT : 45
__DERIVATION : {CIM_Process, CIM_LogicalElement, CIM_ManagedSyste
mElement}
__SERVER : NEWMRED
__NAMESPACE : root\cimv2
__PATH : \\NEWMRED\root\cimv2:Win32_Process.Handle="588"
Caption : notepad.exe
CommandLine : "C:\Windows\system32\notepad.exe"
CreationClassName : Win32_Process
CreationDate : 20110802191720.281486-240
CSCreationClassName : Win32_ComputerSystem
CSName : NEWMRED
Description : notepad.exe
ExecutablePath : C:\Windows\system32\notepad.exe
ExecutionState :
Handle : 588
HandleCount : 61
InstallDate :
KernelModeTime : 156001
MaximumWorkingSetSize : 1380
MinimumWorkingSetSize : 200
Name : notepad.exe
OSCreationClassName : Win32_OperatingSystem
OSName : Microsoft Windows 7 Ultimate |C:\Windows|\Device\H
arddisk0\Partition2
OtherOperationCount : 67
OtherTransferCount : 198
PageFaults : 1362
PageFileUsage : 1972
ParentProcessId : 6324
PeakPageFileUsage : 1972
PeakVirtualSize : 72261632
PeakWorkingSetSize : 5308
Priority : 8
PrivatePageCount : 2019328
ProcessId : 588
QuotaNonPagedPoolUsage : 7
QuotaPagedPoolUsage : 149
QuotaPeakNonPagedPoolUsage : 7
QuotaPeakPagedPoolUsage : 150
ReadOperationCount : 0
ReadTransferCount : 0
SessionId : 1
Status :
TerminationDate :
ThreadCount : 1
UserModeTime : 0
VirtualSize : 72261632
WindowsVersion : 6.1.7601
WorkingSetSize : 5435392
WriteOperationCount : 0
WriteTransferCount : 0
ProcessName : notepad.exe
Handles : 61
VM : 72261632
WS : 5435392
Path : C:\Windows\system32\notepad.exe
After I have the instance of the notepad process I want to terminate, I have at least four choices:
- I can call the method directly using dotted notation (because there is only one instance of the notepad process).
- I can store the reference in a variable, and then terminate it directly.
- I can use the Invoke-WMIMethod cmdlet.
- I can use the [WMI] type accelerator.
You will notice that each time the method is called, a ReturnValue property is returned from the method call. This value is used to determine if the method completed successfully. Return codes are documented for the Terminate method on MSDN (each method will have its return codes detailed on MSDN):
PS C:\> (Get-WmiObject win32_process -Filter "name = 'notepad.exe'").Terminate()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
PS C:\> notepad
PS C:\> $a = Get-WmiObject win32_process -Filter "name = 'notepad.exe'"
PS C:\> $a.Terminate()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
If I want to use the Windows PowerShell Invoke-WMIMethod cmdlet to call an instance method, I must pass a path to the instance to be operated upon. The easiest way to obtain the path to the instance is to first perform a WMI query, and then use the __RelPath system property. The __RelPath system property contains the relative path to the instance of the class. This is shown here:
PS C:\> notepad
PS C:\> $a = Get-WmiObject win32_process -Filter "name = 'notepad.exe'"
PS C:\> $a.__RELPATH
Win32_Process.Handle="5676"
If I am working against a remote machine, I will want the complete path to the instance. The complete path includes the computer name, the WMI namespace, and the class and the key to the class. The complete path is shown in the __Path system property as shown here (do not get confused—the Win32_Process WMI class also contains a path property):
PS C:\> $a.__path
\\NEWMRED\root\cimv2:Win32_Process.Handle="5676"
As shown here, I first create an instance of the notepad process, use the Get-WmiObject cmdlet to retrieve that instance of the process, display the value of the __RELPATH property, and then call the Invoke-WmiMethod cmdlet. When calling the Invoke-WmiMethod cmdlet, I pass the path to the instance and the name of the method to utilize. This is shown in the following commands:
PS C:\> notepad
PS C:\> $a = Get-WmiObject win32_process -Filter "name = 'notepad.exe'"
PS C:\> $a.__RELPATH
Win32_Process.Handle="2008"
PS C:\> Invoke-WmiMethod -Path $a.__RELPATH -Name terminate
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
Another way to call an instance method is to use the [WMI] type accelerator, which works with WMI instances. Therefore, if I pass a path to the [WMI] type accelerator, I can call instance methods directly. In the example that appears here, I start an instance of the notepad process. Next, I use the Get-WmiObject cmdlet to retrieve all instances (there is only one instance) of notepad. Next, I pass the value of the __RELPATH system property to the [WMI] type accelerator. This command returns all of the properties associated with Win32_Process (the same properties seen earlier in this article) for the specific instance of Win32_Process that is indicated by the __RelPath system property. I therefore select only the name property from the object. To this point, I have illustrated that I can retrieve a specific instance of a Win32_Process WMI class via the [WMI] type accelerator. Therefore, it is time to call the Terminate method. This technique is shown here:
PS C:\> notepad
PS C:\> $a = Get-WmiObject win32_process -Filter "name = 'notepad.exe'"
PS C:\> [wmi]$a.__RELPATH | select name
name
----
notepad.exe
PS C:\> ([wmi]$a.__RELPATH).terminate()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
This series of commands and their associated output are shown in the following figure.
ET, that is all there is to using WMI instance methods. WMI Week will continue tomorrow when I will talk about working with WMI Static methods.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy