Get-Service | Add-Member ScriptMethod ToString { $this.Name } -Force -PassThru | Group-Object Status ?To get an understanding of how ScriptMethod is being used here I started reversing the one-liner. I know, from the help, that Get-Member's MemberType parameter allows you to specify ScriptMethod, but, hadn't really seen any practical working examples. The help notes this:ScriptMethod: A method whose value is the output of a script.I Googled around quickly and found one of Dmitry Sotnikov's post:http://dmitrysotnikov.wordpress.com/2008/08/27/select-object-vs-add-member/which opened up entirely different directions to research/test, but, he gave a practical example of how Add-Member works, but, not ScriptMethod. Next, I found this, which not only explains it, but, shows how it works and touches on -PassThru (one of my little personal unknowns):
http://get-powershell.com/post/2009/02/18/A-Method-to-the-Add-Member-Madness.aspxFrom reading Andy's post I learned the following about ScriptMethod:
- when using ScriptMethod the method automatically references $this. He touches on what $this is briefly: "$this refers to the current object. It is similar to the "this" keyword in C#."
- you can explicitly declare a new variable of type [ScriptBlock], but, if it's left out, it is automatically assumed by the system that you are passing something of this type.
.GetType() (or, foreach and .GetType() if I am dealing with a collection) and Get-Member. Knowing what you're dealing with and it's members is fundamental to getting things down. In this case, I went with the first cmdlet and got this:(Get-Service).GetType()returns:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.ArraySo,
Get-Service | Get-Memberwould return a list of
System.Array members. Not what I was hoping for. Let's try this again. This is one of those cases, where we are dealing with collections, so, I wanted to look at one object in the collection (the old one versus many dilemma). Using this syntax(Get-Service | Select-Object -First 1).GetType()I get a very different result from GetType()IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ServiceController System.ComponentModel.Componentand | Get-Member,(Get-Service | Select-Object -First 1) | Get-Member
TypeName: System.ServiceProcess.ServiceController
Name MemberType Definition
---- ---------- ----------
Name AliasProperty Name = ServiceName
RequiredServices AliasProperty RequiredServices = ServicesDependedOn
Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
Close Method System.Void Close()
Continue Method System.Void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose Method System.Void Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method System.Void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Pause Method System.Void Pause()
Refresh Method System.Void Refresh()
Start Method System.Void Start(), System.Void Start(string[] args)
Stop Method System.Void Stop()
ToString Method string ToString()
WaitForStatus Method System.Void WaitForStatus(System.ServiceProcess.ServiceControllerStatus desi...
CanPauseAndContinue Property System.Boolean CanPauseAndContinue {get;}
CanShutdown Property System.Boolean CanShutdown {get;}
CanStop Property System.Boolean CanStop {get;}
Container Property System.ComponentModel.IContainer Container {get;}
DependentServices Property System.ServiceProcess.ServiceController[] DependentServices {get;}
DisplayName Property System.String DisplayName {get;set;}
MachineName Property System.String MachineName {get;set;}
ServiceHandle Property System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
ServiceName Property System.String ServiceName {get;set;}
ServicesDependedOn Property System.ServiceProcess.ServiceController[] ServicesDependedOn {get;}
ServiceType Property System.ServiceProcess.ServiceType ServiceType {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
Status Property System.ServiceProcess.ServiceControllerStatus Status {get;}Alright, now we're cooking with grease. I know exactly what I get from cmdlet 1. Now, let's add a member and get the type:(Get-Service | Add-Member -MemberType ScriptMethod ToString { $this.Name } -Force -PassThru | Select-Object -first 1).GetType()returns this, which as to be expected, is the same as the definition above,IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False ServiceController System.ComponentModel.ComponentThere's actually a lot that goes into this line. The Add-Member cmdlet is adding a new ScriptMethod to the object called ToString. The ScriptMethod, which, remember, is of type [ScriptBlock], has the definition.ToString { $this.Name }So, when we select the object after the member has been added, using the Select-Object cmdlet, it adds a new ScriptMethod member. We can verify this by looking at the pipelined command and using Get-Member. To do this, I use this command,(Get-Service | Add-Member -MemberType ScriptMethod ToString { $this.Name } -Force -PassThruand it returns, TypeName: System.ServiceProcess.ServiceController
Name MemberType Definition
---- ---------- ----------
Name AliasProperty Name = ServiceName
RequiredServices AliasProperty RequiredServices = ServicesDependedOn
Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
Close Method System.Void Close()
Continue Method System.Void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose Method System.Void Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method System.Void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Pause Method System.Void Pause()
Refresh Method System.Void Refresh()
Start Method System.Void Start(), System.Void Start(string[] args)
Stop Method System.Void Stop()
WaitForStatus Method System.Void WaitForStatus(System.ServiceProcess.ServiceControllerStatus desi...
CanPauseAndContinue Property System.Boolean CanPauseAndContinue {get;}
CanShutdown Property System.Boolean CanShutdown {get;}
CanStop Property System.Boolean CanStop {get;}
Container Property System.ComponentModel.IContainer Container {get;}
DependentServices Property System.ServiceProcess.ServiceController[] DependentServices {get;}
DisplayName Property System.String DisplayName {get;set;}
MachineName Property System.String MachineName {get;set;}
ServiceHandle Property System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
ServiceName Property System.String ServiceName {get;set;}
ServicesDependedOn Property System.ServiceProcess.ServiceController[] ServicesDependedOn {get;}
ServiceType Property System.ServiceProcess.ServiceType ServiceType {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
Status Property System.ServiceProcess.ServiceControllerStatus Status {get;}
ToString ScriptMethod System.Object ToString();Notice the last line, ToString. This is what we accomplished with the Add-Member cmdlet. Yet, I didn't touch on the two addition parameters: -PassThru and -Force. As outlined in Get-Help,Get-Help Add-Member -Parameter Passthru
-PassThru []
Passes the newly extended object to the pipeline. By default, this cmdlet does not generate any output.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false As it was explained to me, this is the same thing C# does when returning the object by specifying the datatype instead of void. In practice, this adds the new member, but, returns no result to be handle except for the extended object. -PassThru, from my understanding, is a part of the Extended Type System. If you do not add -PassThru to the command outlined in this example, it will fail to return anything:(Get-Service | Add-Member -MemberType ScriptMethod ToString { $this.Name } -Force | Select-Object -first 1) | Get-Memberreturns nothing. We can verify this with .GetType().(Get-Service | Add-Member -MemberType ScriptMethod ToString { $this.Name } -Force | Select-Object -first 1).GetType()throws this error:You cannot call a method on a null-valued expression.
At line:1 char:116
+ (Get-Service | Add-Member -MemberType ScriptMethod ToString { $this.Name } -Force | Select-Object -first 1).GetType < <<< () + CategoryInfo : InvalidOperation: (GetType:String) [], RuntimeExceptionAaron Nelson also pointed me to this post to get a little further clarification on its usage:http://powershell.com/cs/blogs/tips/archive/2009/08/26/adding-custom-properties.aspxThe
-Force parameter merely causes the change to occur regardless of any objections by Powershell.Get-Help Add-Member -Parameter Force
-Force []
Adds a new member even if one with the same name already exists. Does not work for core members of a type.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false The last portion of the script above, Group, is well-documented, so, I won't worry about it too much.
0 comments:
Post a Comment