PowerShell Basics–Objects and the Pipeline
By now you would have noticed if you have been reading my other posts where I use PowerShell that it is not your typical Shell and that it behaves in a unique way when it comes to the output generated by the commands we issue in it, this is because PowerShell is an Object based Shell, this means that everything is an object. Those that have programed in Perl, Ruby, Python, C# or any other Objects based language know very well the power of objects, for those that come from a Bash, cmd.exe or any other regular text based shell you will notice that in PowerShell is a lot simpler to parse and use data, typically on one of this shells we are searching for strings, extracting the strings of text that we need and then piping them to something else, this can be very labor intensive. Lets start by defining what an Object is simple terms, an object is Data and it has 2 types of components:
- Properties – Information we can retrieve and/or set by name.
- Method – something we can have happen to the data, it can take arguments to determine what to do or to provide additional information.
Get-Service | Get-Member
This will produce a list of:
- Properties – Information about the object.
- Methods – Things we can do to the objects.
- ScriptMethods – Pieces of embedded code that will execute when called.
- Events – Things that happen to an object we can subscribe to be notified when they happen.
It will also tell us what is the .Net Object Class it is being returned.
While using this you may noticed that for some outputs of commands you will see more than one Object Class, Get-Member is smart enough to only show the info for the unique classes that are returned. Lets look at the information we can get from a single object, for the example I will use the BITS service so as to not break my machine. Lets start by saving it in to a variable so it is easier to manipulate. Variables in PowerShell are maded with a $ in the front just like in Perl .
$BITSSrv = Get-Service -Name BITS
Now lets start with the fun part, the methods. To see what we can do with the object we use the Get-Member cmdlet but specify that we want only the methods shown:
PS C:\> $BITSSrv | Get-Member -MemberType Method
TypeName: System.ServiceProcess.ServiceControllerName MemberType Definition
---- ---------- ----------
Close Method void Close()
Continue Method void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type reque...
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Pause Method void Pause()
Refresh Method void Refresh()
Start Method void Start(), void Start(string[] args)
Stop Method void Stop()
WaitForStatus Method void WaitForStatus(System.ServiceProcess.ServiceContro...
As we can see there are several actions we can take against the service object, we can start, stop, pause, refresh (The object is only the state of what it represents at the given time we retrieved it). Wehn we look at the definitions we can see it shows us that some methods like Pause and Refresh do not take any arguments and others like Start can be called in several ways in some without us giving it arguments in others it tells us the type of class the method will take. Some can be deduce quite easily others we have to look in the MSDN Website for the class information (ServiceController Class) do the way output is formatted we may loose some of the info we may need. for this we can use one of the Format Cmdlets to make it wrap the line so we can have a better look.
PS C:\> $BITSSrv | Get-Member -MemberType Method | Format-Table -Wrap
TypeName: System.ServiceProcess.ServiceControllerName MemberType Definition
---- ---------- ----------
Close Method void Close()
Continue Method void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type
requestedType)
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Pause Method void Pause()
Refresh Method void Refresh()
Start Method void Start(), void Start(string[] args)
Stop Method void Stop()
WaitForStatus Method void WaitForStatus(System.ServiceProcess.ServiceControlle
rStatus desiredStatus), void WaitForStatus(System.Service
Process.ServiceControllerStatus desiredStatus, timespan
timeout)
Lets stop the service:
PS C:\> $BITSSrv.Stop()PS C:\> $BITSSrv.Status
RunningPS C:\> $BITSSrv.Refresh()
PS C:\> $BITSSrv.Status
Stopped
As it can be seen I forgot that when the object is in a variable it is just a representation at the moment it was saved. Let look at Parenthetical execution go get around this, when we wrap the command around ( ) we can use the properties and methods of the object it returns directly.
PS C:\> (Get-Service -Name BITS).Start()PS C:\> (Get-Service -Name BITS).Status
Running
Now since we are poling the information on each command we get the latest information. You can notice from the examples that Properties do not require ( ) at the end of invocation and Methods do, just something to keep in mind, in fact using tab completion or the ISE it will remind you.
Let look at the properties:
PS C:\> Get-Service -Name BITS | Get-Member -MemberType Property
TypeName: System.ServiceProcess.ServiceControllerName MemberType Definition
---- ---------- ----------
CanPauseAndContinue Property bool CanPauseAndContinue {get;}
CanShutdown Property bool CanShutdown {get;}
CanStop Property bool CanStop {get;}
Container Property System.ComponentModel.IContainer Container {get;}
DependentServices Property System.ServiceProcess.ServiceController[] DependentServices ...
DisplayName Property string DisplayName {get;set;}
MachineName Property string MachineName {get;set;}
ServiceHandle Property System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
ServiceName Property string ServiceName {get;set;}
ServicesDependedOn Property System.ServiceProcess.ServiceController[] ServicesDependedOn...
ServiceType Property System.ServiceProcess.ServiceType ServiceType {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
Status Property System.ServiceProcess.ServiceControllerStatus Status {get;}
You will notice that some of the properties have in the end {get;set} or only {get;} this means we can assign a value to the property of the same type as it is listed in the definition. Since PowerShell will only list some of the properties depending on the formatting it has defined. Do take in to account this is only for the instance of the object, we would not be changing the service it self but the representation we may have in a variable. To change the service itself it would have to be thru a Method.
The formatting of what is displayed is shown following the guidelines shown in the format.pmxml file for each type in the Windows PowerShell folder, for the service it would be in C:\Windows\System32\WindowsPowerShell\v1.0 since the view is sometimes limited and we want to do a quick browse of all that is in the properties we can use the formatting cmdlets to exposed all, I tend to use the Format-List cmdlet:
PS C:\> Get-Service -Name BITS | Format-List -Property *
Name : BITS
RequiredServices : {RpcSs, EventSystem}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
DisplayName : Background Intelligent Transfer Service
DependentServices : {}
MachineName : .
ServiceName : BITS
ServicesDependedOn : {RpcSs, EventSystem}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
Site :
Container :
PipeLine
By now you would have noticed in this blogpost and others that the pipeline is used quite a bit in PowerShell. The typical pipeline in other shells will move the standard out of a command to the standard input of another:
In the case of PowerShell we are moving objects so there are 2 ways a cmdlet can receive commands from the pipeline:
- By Value – this is where the output of a cmdlet must be the same type as what the –InputObject parameter of another takes:
- By Property Name – This is when the object has a property that matched the name of a parameter in the other.
So by Value would be:
And when we look at the parameters in help we can identify them by looking of they accept from the pipeline and how:
By Property it would be:
and when we look at the help information for the parameter it would look like:
The examples above are from the Service cmdlets so we could just pipe the Get-Service cmdlet any of the other cmdlets for managing services:
PS C:\> gcm *service* -Module Microsoft.PowerShell.ManagementCommandType Name ModuleName
----------- ---- ----------
Cmdlet Get-Service Microsoft.PowerShell.Man...
Cmdlet New-Service Microsoft.PowerShell.Man...
Cmdlet New-WebServiceProxy Microsoft.PowerShell.Man...
Cmdlet Restart-Service Microsoft.PowerShell.Man...
Cmdlet Resume-Service Microsoft.PowerShell.Man...
Cmdlet Set-Service Microsoft.PowerShell.Man...
Cmdlet Start-Service Microsoft.PowerShell.Man...
Cmdlet Stop-Service Microsoft.PowerShell.Man...
Cmdlet Suspend-Service Microsoft.PowerShell.Man...
So this would allow us to do:
PS C:\> Get-Service -Name BITS | Stop-ServicePS C:\> (Get-Service -Name BITS).Status
StoppedPS C:\> Get-Service -Name BITS | Start-Service
PS C:\> (Get-Service -Name BITS).Status
Running
I hope that you found this blog post in the series useful and on the next one we will cover how to filter and process the Objects generated so we can glue even more types of cmdlets together.