::::::::: PowerShell :::::::::
Tuesday, June 13, 2006
  Getting Services associated with a Process via PowerShell (.NET Type Extension)
On a recent Microsoft.Public.Windows.PowerShell NG (Newsgroup) posts, Andrew Watt has asked for an "Equivalent [cmdlet] for tasklist /svc".

Luckily, Abhishek has posted a blog entry concerning that very problem a couple of weeks ago as "Getting Services associated with a Process via PowerShell" on May 18, 2006.

According to Abhishek, "the Cmdlet implementation relies on System.Diagnostics.Process class in .Net which unfortunately does not expose this information", so he has utilized WMI object Win32_Service to retrieve service information associated with a process.

Abhishek has approached to the problem with a function, plist, to iterate each System.Diagnostics.Process object instance type and match each process against service information retreived through Win32_Service, and the append a NoteProprety to each "System.Diagnostics.Process" object instances.

But then, I just wanted more intuitive way(well i just wanted to mess around...) to retrieve "Service" information associated with a process id and .. Ta~da~... There was types.ps1xml...
One of the beauties of PowerShell is that, you can extend .NET types as you want. (Anyways, for more links concerning Type Extension feature and articles, go to http://del.icio.us/powershell/TypeExtension...)

This time, I have yet again, tried to extend another .NET type, System.Diagnostics.Process as I did in previous post( [MSH] Extending System.Security.SecureString ).

... Other membersets and properties ...
$svc = @(, (Get-WmiObject Win32_Service -Filter "ProcessId='$($this.Id)'" | Group-Object ProcessId).Group)
if ($svc[0] -eq $null) { "N/A" } else { $svc }

Ok, now let's see. What's going on here?
In $pshome\types.ps1xml, I am extending System.Diagnostics.Process type (System.Diagnostics.Process) to include a ScriptProperty () which contains a script block () to retrieve Service information associated with current Process's id ($this.Id) from Win32_Service WMI object.

The reason I have added the "if" statement on the second line in is because when you run "tasklist /svc", if there is no service(s) associated with a process ID, it is returned as "N/A".

There are two gotchas, here that you have to be careful of.
  1. $svc = @(, (Get-WmiObject ...
  2. if ($svc[0] ...
For the first case, I am actually including a null object to force an array with one item to be interpreted as an array with multiple items.
To illustrate the point, let's see the following case.
[^_^]PS[142]>$a = @(1)
[^_^]PS[143]>$a | Get-Member
TypeName: System.Int32
Name MemberType Definition
---- ---------- ----------
CompareTo Method System.Int32 Compa
[^_^]PS[144]>, $a | Get-Member
TypeName: System.Object[]
Although I have declared $a as an array of one item, "Get-Member" will return "System.Int32" , which is the type of the array item(1), as its TypeName for $a although most of people would expect an array type to be returned. Anyways, there was this NG post or a blog entry that dealt with this problem and I will try to update the blog later on for links concerning this problem.

For the second problem, well, I was checking for "$svc.Length -lt 1" but it turns out that, $svc.Length is always equal to or great than 1 because $svc will always contain a null object.(this is not that clear of an explanation... since I haven't understood this clearly, yet)

Why did I even bother going through the gotchas?
Well, if i hadn't used "@(, (Get-Wmi..." and used just "@(Get-Wmi..." then what you might get is something as ugly as

[^_^]PS[10]>gps svchost | select name,id,service | ft -auto

Name Id Service
---- -- -------
SVCHOST 972 {DcomLaunch, TermService}
SVCHOST 1072 \\IT03\root\cimv2:Win32_Service.Name="RpcSs"
SVCHOST 1204 \\IT03\root\cimv2:Win32_Service.Name="Dnscache"
SVCHOST 1264 {Alerter, LmHosts, SSDPSRV, WebClient}
SVCHOST 1284 {AppMgmt, AudioSrv, BITS, Browser...}
SVCHOST 3540 \\IT03\root\cimv2:Win32_Service.Name="stisvc"
SVCHOST 3772 \\IT03\root\cimv2:Win32_Service.Name="usnsvc"

where you see a full type name for Service property with only ONE service associated thereof.

The reason for the "if" is hmm well, if you run "tasklist /svc", for process Id's with no associated service(s), it returns "N/A" so I just wanted to mimic the behavior...

Well, that's it folks...
Ah, lastly, I have to tell you that running "Get-Process | Select-Object name,id,service" takes quite a long time(about 4 seconds!!! compared to 0.3 & 0.2 seconds by "tasklist /svc" and "plist" function). It is defniately not an efficient way to retrieve Service information associated with a process id. Extend your type and have fun at your own risk... ;)

[^_^]PS[2]>Measure-Command { Get-Process | Select-Object name,id,service }

Days : 0
Hours : 0
Minutes : 0
Seconds : 4
Milliseconds : 198
Ticks : 41988791
TotalDays : 4.85981377314815E-05
TotalHours : 0.00116635530555556
TotalMinutes : 0.0699813183333333
TotalSeconds : 4.1988791
TotalMilliseconds : 4198.8791

[^_^]PS[3]>Measure-Command { tasklist /svc }

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 244
Ticks : 2440259
TotalDays : 2.82437384259259E-06
TotalHours : 6.77849722222222E-05
TotalMinutes : 0.00406709833333333
TotalSeconds : 0.2440259
TotalMilliseconds : 244.0259

[^_^]PS[4]>Measure-Command { plist * | Format-Table name,id,service }

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 341
Ticks : 3419322
TotalDays : 3.95754861111111E-06
TotalHours : 9.49811666666667E-05
TotalMinutes : 0.00569887
TotalSeconds : 0.3419322
TotalMilliseconds : 341.9322

Tags :
Great post! showing the power of Type Extensions... truly ETS is in some sense "liberating"

Thank you for the feedback there ;)

Extended Type System came as a shock when i first saw it so a lot of times, although there is no reason for me to do so, i tend to modify the types just hmmm, for fun ;)
"Democracy to the types !!"

(c)"More Talking on Monad" ,Jeffrey Snover

So a powerfull and a dynamic Shell (Language)


Yep we are there ;-)

gr /\/\o\/\/

gr /\/\o\/\/
Post a Comment

<< Home
Let's get lazy with PowerShell!

Location: Flushing, NY, United States

Experimenting with a different format of blogs...

10/01/2005 - 11/01/2005 / 11/01/2005 - 12/01/2005 / 12/01/2005 - 01/01/2006 / 01/01/2006 - 02/01/2006 / 02/01/2006 - 03/01/2006 / 03/01/2006 - 04/01/2006 / 04/01/2006 - 05/01/2006 / 05/01/2006 - 06/01/2006 / 06/01/2006 - 07/01/2006 / 07/01/2006 - 08/01/2006 / 08/01/2006 - 09/01/2006 / 10/01/2006 - 11/01/2006 / 11/01/2006 - 12/01/2006 /

Powered by Blogger