Use PowerShell to Explore Process Threads in Windows

Use PowerShell to Explore Process Threads in Windows

  • Comments 5
  • Likes

Summary: Microsoft Scripting Guy talks about using Windows PowerShell to explore process threads in Windows.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a problem. On our system, every once in a while, we have this application where the threads go crazy. I need an easy way to check threads. Can you help?

—BC

Hey, Scripting Guy! Answer Hello BC,

Microsoft Scripting Guy, Ed Wilson, is here. Well it is official; there will be a Microsoft Scripting Guy booth at TechEd 2013 in New Orleans. The Scripting Wife will also be at the booth. We are planning to share our booth with the Windows PowerShell community from PowerShell.org as well. It will be a lot of fun, and we are already looking forward to it. The dates for TechEd 2013 in New Orleans, by the way, are June 3 – June 6.

Use WMI to find info about threads

To find information about threads, I use the Win32_Thread WMI class. I found this by using the Get-CimClass cmdlet as shown here.

Get-CimClass *thread*

The command and its associated output are shown in the following image.

Image of command output

I can also do the same thing by using the Get-WmiObject cmdlet. This technique is shown here.

Get-wmiobject -list *thread*

So, I decide to query the WMI class. Here is the Windows PowerShell 2.0 version of the command.

Get-WmiObject win32_thread

I can do the same thing with the CIM cmdlets in Windows PowerShell 3.0. This command is shown here.

Get-CimInstance win32_thread

The command and the output from the command are shown here.

 Image of command output

Find a specific thread

The easiest way to find a specific thread is to first get the process handle, and then use that handle in a WMI filter. The following command obtains the handle for a running instance of Notepad, and then obtains the thread information.

$handle = (Get-Process notepad).handle

Get-WmiObject win32_thread -filter "handle = $handle"

By using the Get-CimInstance Windows PowerShell 3.0 CIM cmdlet, I arrive at the following syntax.

$handle = (Get-Process notepad).handle

Get-CimInstance win32_thread -filter "handle = $handle"

There is very little difference between the two commands. There is a bit of a difference between the output from the two commands. The output from the Get-CimInstance cmdlet is cleaner. The command and output from Get-CimInstance is shown here.

Image of command output

To understand the thread state, it is necessary to look up the ThreadState property. I can do this in the MSDN article, Win32_Thread WMI class. The ThreadState values are shown here.

Value

Meaning

0

  Initialized. It is recognized by the microkernel.

1

  Ready. It is prepared to run on the next available processor.

2

  Running. It is executing.

3

  Standby. It is about to run. Only one thread may be in this state at a time.

4

  Terminated. It is finished executing.

5

  Waiting. It is not ready for the processor. When ready, it will be rescheduled.

6

  Transition. The thread is waiting for resources other than the processor.

7

  Unknown. The thread state is unknown.

The ThreadWaitReason value codes are shown in the table that follows. 

Value

Meaning

0

Executive

1

FreePage

2

PageIn

3

PoolAllocation

4

ExecutionDelay

5

FreePage

6

PageIn

7

Executive

8

FreePage

9

PageIn

10

PoolAllocation

11

ExecutionDelay

12

FreePage

13

PageIn

14

EventPairHigh

15

EventPairLow

16

LPCReceive

17

LPCReply

18

VirtualMemory

19

PageOut

20

Unknown


BC, that is all there is to using Windows PowerShell and WMI to find information about threads. Join me tomorrow when I will talk about more cool stuff.Therefore, the Notepad process is waiting and not ready for the processor. The reason it is waiting is EventPairLow.

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 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hey.

    Cool stuff - thank you.

    I've got a PS script that hangs during execution, and looking closer at the process and threads I find a seemingly undocumented value for the ThreadWaitReason. Is there anywhere to lookup "other" reasons than 0-20?

    I'm running PS 3 on a Server 2012, and I find:

    ThreadState              : 5

    ThreadWaitReason         : 37

    Thanks.

  • The docs say:

    Reason why the thread is waiting. This value is only valid if the ThreadState member is set to Waiting (6). Event pairs allow communication with protected subsystems.

  • So I was having a lot of issues with your above example at first, mostly wondering why you were comparing the notepad.exe handle to the thread's handle and not the thread's process handle.  Needless to say, I think in your example you may have just luckily have gotten a result (or you did this in powershell 3.0 exclusively and tried to translate to 2.0 and some of the properties between the returned objects are different).  I found the following to work to return ALL threads of a process in 2.0...

    $ID = (Get-Process notepad.exe).ID

    Get-WmiObject win32_thread -filter "Processhandle = $ID"

  • @quickflash - you need to understand how Get-Process works:

    Get-Process does NOT use a file extension for the process name.  In  V2 you cannot use the shortcut.  This works in all versions.

    $process_ids=Get-Process notepad |%{$_.ID}

    foreach($id in $process_ids){

        Get-WmiObject Win32_Thread -filter "ProcessHandle=$id"

    }

    This resolves the issue of multiple processes with same name.

    You are correct about 'handle'.

  • How can I translate the "Start address" of a thread to Function names like we see in Process explorer. Is there any way to achieve that thru Powershell. Like as below. TID 2372 CPU 1.04 Cycles Delta 116,034,781 StartAddress SHCORE.dll!Microsoft::WRL::Details::ImplementsHelper,Microsoft::WRL::Details::InterfaceList,Microsoft::WRL::Details::InterfaceList<Microsoft::WRL::CloakedIid<CFTMCrossProcServer