Services and processes seem to be a constant source of topics for PowerShell. Probably because they are so fundamental to Windows. I wanted to see the relationship between a service and its underlying process.
001
002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 |
##Requires -version 2.0
## create empty array $data = @() ## create class for object $source=@" public class ServProc { private string _servicename; private string _displayname; private string _processname; private int _processid; public string DisplayName { get {return _displayname;} set {_displayname = value;} } public string ServiceName { get {return _servicename;} set {_servicename = value;} } public string ProcessName { get {return _processname;} set {_processname = value;} } public int ProcessId { get {return _processid;} set {_processid = value;} } } "@ Add-Type -TypeDefinition $source Get-WmiObject -Class Win32_Service | foreach { $data += $sp } |
What we need to do is get the services and find the process id and use that to match it to the underlying process. This sort of problem I would usually create an object and then use add-member to add the properties as we loop through the services.
I decided to have a go with Add-Type instead.
Add-Type is cmdlet new to PowerShell version 2. If you are not a programmer you possibly looked at the help information, shuddered and moved on. I have done a bit of C# programming but don’t class myself as a programmer (bet all programmers reading this are looking at the class definition as saying – yep). As far as I’m concerned if it works its good.
So we start with Requires so that don’t try and run this in version 1.
We can then create an empty array. So far so good.
The next bit is where we create a .NET class. A class is what we use when we create an object – think of it in this case as a template. The stuff in the here string $source=@”………..”@ is the C# code that defines the class.
public means that we can access it. ServProc is its name. We then have four properties which are created
public string DisplayName {
get {return _displayname;}
set {_displayname = value;}
}
by supplying a name eg Displayname and a data type eg string. We also supply a get and set which do what they say. Set is usewd when we set the property and get when we read it. The
private string _displayname;
in effect defines a private variable that is used inside the class. C# IS CASE SENSITIVE!!! and expects a ; as a line terminator
Add-Type is used to create the class.
The Win32_Service WMI class can be used to get the service side information. We create a new object using our class and then set the properties. Notice that we can use the properties of the object as soon as we have created it to get the process name.
Our object is added to the array and we loop for the next service.
Final line of the script displays the data .
The hardest part of using add-type is remembering how to define the properties in C#. Is it worth doing this compared to Add-Member?
It makes the working part of the script neater but makes the earlier part more complicated. If you are not happy with C# probably not for you though other languages can be used. On the other hand if all you want is an object with some properties you have a template here that can be re-used. Just create a private variable for each property and make sure you get the data type right.
Will I use this instead of Add-Member – probably. Especially where I am creating a module with a number of functions that will use the same object.
It wasn’t as difficult as I thought – but I would definitely put this in the advanced PowerShell bucket for now.