Working with objects in PowerShell
Useful Tool
If you want to professionally manage Windows systems, and above all servers, it's hard to avoid using PowerShell. Many admins, however, find it somewhat difficult to cope with the object-oriented approaches of the scripting language. Our workshop provides assistance and illuminates the fundamental concepts.
Of course, admins use scripting languages to handle administrative and support tasks, and many system administrators will have had no alternative but to delve the depths of the SQL language. Basically, most administrators want to do their jobs rather than develop programs, which explains why many experienced Windows admins have a certain aversion to working with PowerShell. This is particularly unfortunate, because this language can significantly facilitate the work, specifically because of its structure and object-oriented approach (see the "Object-Oriented Structure in PowerShell" box for more information). The motivation behind this article is thus to show how the developers implemented this concept and how the scripting language uses these objects.
Object-Oriented Structure in PowerShell
The foundation of PowerShell comprises special .NET classes that make it possible to use the entire .NET library from within the PowerShell environment. The cmdlets available directly in the PowerShell environment run perform specified actions, such as enumerating the files in a directory or managing a system service.
The cmdlets for PowerShell objects typically return objects, although there are some exceptions. The cmdlets perform an action of this type by creating an object or a group of objects based on the specialized PowerShell classes. They then provide the functions available, with the help of which, for example, the information can be routed through the pipeline and used by other commands.
Often the problem for users is to imagine something in terms of the fairly abstract concept of objects. A way better to clarify this description is to imagine each of these objects as a package of related information. An object can include, for example, the data need to describe a file: the name and size of the file, the file storage location, and other attributes.
Working with Objects
If you want to work with the data of an object, you need to call its members . These are the components that let you access and edit the information. A PowerShell object supports a whole range of members, the most famous examples being properties and methods . When you work with objects, you use the methods to perform actions, and the properties, to access information. An object's properties include, for example, values such as the file size or the date on which the file was created, whereas deleting or moving the file is one of the methods provided by the respective object.
If you want to learn and understand more about the concepts and capabilities of PowerShell, your best bet – as with any scripting and programming language – is to try the examples yourself. One of the PowerShell cmdlets that people like to use for this purpose is Get-Service
. It outputs a list of the services installed on a computer. If called without any parameters, the cmdlet also outputs details about the services on the local system.
Each service that is returned by the Get-Service
cmdlet is an object based on the .NET System.ServiceProcess.ServiceController
class. Of course, the ServiceController
object also includes a number of properties and methods that a user can draw on to access the data in the object or perform operations against the data. They include, for example, the properties of the name and the DisplayName
of the system service. The value associated with the properties of DisplayName
is the display name of the service. The ServiceController object also provides a number of methods: You can use the Start method to start the service represented by the object and the Stop method to stop it again.
It is unlikely that an admin could memorize all the properties, methods, or even member types of the objects to access and use them correctly. PowerShell thus provides a tool that helps you retrieve detailed information about the respective members of an object: the Get-Member
cmdlet. If you want to know, for example, which members the get-service
cmdlet provides, you can retrieve this information by typing:
> Get-Service | Get-Member
The objects that Get-Service
returns are piped (as represented by the |
character) to the input of the Get-Member
cmdlet (Figure 1). The following output shows what members, methods, and properties a cmdlet provides. The list includes the name of each member, its type, and a definition. To what extent this definition is useful for you, depends to a large extent on your programming skills. In any case, you can determine in this way that Service.Controller
comes with a whole bunch of members and also see their names. Also, this example shows very nicely that these are mostly methods and properties of the respective object.
Detailed Information on Objects
For users, who are already familiar with the .NET classes, this output is worth a closer look. It first displays the type name of the class on which this object is based – in this case, System.ServiceProcess.ServiceController
. There is another, very interesting aspect to this information: Inspection of the results returned by Get-Member
shows that they only include the details of a single object, even though the Get-Service cmdlet returns an object for each service. The reason for this is the way the Get-Member
cmdlet works. If it notes that several objects of the same type are returned, it only shows you one instance of these objects in the output. The developers did this to avoid redundancies. The cmdlet only returns the class on which all these objects are based.
If the command does not return more than one object type, Get-Member
displays the appropriate information for each of these types. An example of this is calling the Get-ChildItem
cmdlet for a directory that includes both files and subdirectories (Figure 2):
> Get-ChildItem H:\tmp | Get-Member
Get-Member
now displays details of the classes System.IO.DirectoryInfo
(for directories) and System.IO.FileInfo
(for the files in the directory H:\tmp
). If this directory only contained directories, Get-Member
would display only the details of System.IO.DirectoryInfo
. Users who want to use Get-Member
thus need to ensure that they actually get to see the object types that they are really interested in.
Get-Member
has still more to offer: For example, the user can display a list, consisting of a special member type, such as the properties or the methods. If you need this kind of output, you need to add the -MemberTyp
parameter followed by the name of the desired type in the call. The following call ensures that only the properties of the respective object are displayed on the screen:
> Get-Service | Get-Member -MemberTyp Property
The ability to specifically request such details makes it easier to access the information within an object. It does not matter whether you are interested in a specific member or a whole list of the members of an object.
Even More Targeted and Detailed
For example, if you already know that the ServiceController
class supports the properties Status
and ServiceTyp
, you can use this information in a targeted way to specify your own commands and their output. For example, the following command uses these properties together with the Where-Object
cmdlet to filter the results as desired:
> Get-Service | Where {$_.Status -eq "Running" `-and $_.ServiceType -eq "Win32OwnProcess"}
Again Get-Service returns a set of ServiceController objects that are then routed through the pipe to the Where-Object
cmdlet. I used the Where
alias for this cmdlet. For each of the objects passed to the Where-Object
cmdlet, you can now access its properties to develop the desired filter. This is why you need to use the $_
symbol. This is a system variable that always points to the current object in the pipeline, which makes it particularly well suited to processing these objects in sequence. This symbol must be followed by a dot, in turn followed by the name of the property; I selected the Status
property here.
You can now use this to return specific data in line with your specifications. To do this, you can use Boolean expressions, which determine whether this information is true or false. In this case, I first stipulated that the Status
property must have a value of Running
and that the ServiceTyp
property must be equal to the value of Win32-OwnProcess
.
In both cases, the -eq
(for "equals") operator is used. With its help, you can determine whether the required values apply. The -and
operator is added to link the two expressions. Based on Boolean logic, both expressions must be "true" and the properties must contain the required value for an object to be returned. An important note about this example: The `
character at the end of the first line tells the PowerShell interpreter to continue the code on the next line. If this is missing, the PowerShell command ends at the end of the line, and you will see an error message.
This is a good example of a user's access to the information that they were originally looking for being facilitated by knowing the names of the properties that are supported by the respective object. If you want to take this example a step further, you can pass the results of the command to the Format-Table
cmdlet:
> Get-Service | Where {$_.Status -eq "Running" `-and $_.ServiceType -eq "Win32OwnProcess"} | `Format-Table -Autosize
This again demonstrates the power of the pipeline mechanism.
Buy this article as PDF
(incl. VAT)