Hey, Scripting Guy! I think I might have a problem on my server. When I go into Task Manager, all the processes that are eating up the most CPU time and the most memory are the stupid svchost.exe process. I know this is the Service Host process and that it is being used by multiple services, but how can I know what is really going on in there?
– JH
Hi JH,
Scripting Guy at your service. Or is it at your Service Host? Yes, I know, I’m eating your CPU time with lame comedy. Let’s go.
To look into the Service Host process, what we need to do is first find all the processes with the name ofsvchost.exe. Next we need to find the handle of each one so we can uniquely identify it. Next we need to find all the services that are using a particular process ID, match them up with the handles we had earlier, and we have your answer. Here is the GetServicesInSvchost.ps1 script:
$aryPid = @(Get-WmiObject win32_process -Filter "name='svchost.exe'") | Foreach-Object { $_.Handle } "There are " + $arypid.length + " instances of svchost.exe running" foreach ($i in $aryPID) { Write-Host "Services running in ProcessID: $i" ; Get-WmiObject win32_service -Filter " processID = $i" | Format-Table name, state, startMode }
Our script begins by using WMI to find all the processes that are named svchost.exe. To do this, we use the Get-WmiObject cmdlet. For each of these processes we find, we obtain the handle and assign the resulting array of handles to a variable aptly named $aryPid. This line of code is seen here:
$aryPid = @(Get-WmiObject win32_process -Filter "name='svchost.exe'") | foreach-object { $_.Handle }
Once we have an array of process IDs for all the svchost processes, we use the length property to count how many we actually have running. This is not important for the actual script; however, it is very important for our sanity. It is also a nice reality check to assure us the script is working properly. For example if the $ary.length is equal to 1, but you see the following in Task Manager, you can be assured you have a problem:
Now we want to walk through the array contained in the $aryPid variable. To do this, we will use the foreach statement. We need to use a variable to keep track of things, we choose the $i variable. This line of code is seen here:
foreach ($i in $aryPID)
To produce a header for our report, we use the Write-Host cmdlet to print out the processID of the current process we are working with, which is represented by the variable $i. We end the line with a semicolon as we want to continue the command. This is seen here:
Write-Host "Services running in ProcessID: $i" ;
We now need to do another WMI query. This time, we will query from the Win32_Service WMI class. We use a filter to limit our query to services that have a particular ProcessID value. We are interested in finding all services that have a ProcessID that is the same as one of our running versions of the Svchost.exe processes. When we find a service with a ProcessID that matches a Svchost.exe process, we have our answer. We decide to organize our data as a table and print out the name, state, and startmode of the service. This line of code is seen here:
Get-WmiObject win32_service -Filter " processID = $i" | Format-Table name, state, startMode
When we run the script, we obtain a report that is similar to the one seen here:
In the end, JH, it did not take super scripting powers after all. It was a rather tame script, and leveraging the ease in which Windows PowerShell does WMI, it was actually pretty short as well. To be perfectly candid, we could have written the script in a single line as seen here:
get-wmiObject win32_process -filter "name='svchost.exe'" | foreach { gwmi -query "Select * from win32_service where processID = $($_.handle)" } | sort processID, Name | format-table processID, name, state, startmode -AutoSize
But it would have been a really long line. Hope this script gives you some x-ray eyes and allows you to remove some of the mystery surrounding the svchost process.
Ed Wilson and Craig Liebendorfer, Scripting Guys
0 comments