Using the PowerShell object cmdlets

PowerShell has some cmdlets that are designed to work with all kinds of objects. You can easily recognize them because they all have the noun Object. You can use the Get-Command cmdlet -Noun parameter to find them:

PowerCLI C:> Get-Command -Noun Object

The preceding command has the following output:

CommandType Name           Version Source
----------- ----           ------- ------
Cmdlet      Compare-Object 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      ForEach-Object 3.0.0.0 Microsoft.PowerShell.Core
Cmdlet      Group-Object   3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Measure-Object 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      New-Object     3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Select-Object  3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Sort-Object    3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Tee-Object     3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Where-Object   3.0.0.0 Microsoft.PowerShell.Core 

In the following section, we will discuss the Object cmdlets.

Using the Select-Object cmdlet

If you want to retrieve a subset of the properties of an object, select unique objects or a specific number of objects or specific objects from an array, you can use the Select-Object cmdlet. You can also use the Select-Object cmdlet to add properties to an object using calculated properties, as you have seen in Chapter 2 , Learning Basic PowerCLI Concepts.

The Select-Object cmdlet has the following syntax. The first parameter set is the default:

Select-Object [[-Property] <Object[]>] [-ExcludeProperty <String[]>] [-ExpandProperty <String>] [-First <Int32>] [-InputObject <PSObject>] [-Last <Int32>] [-Skip <Int32>] [-Unique] [-Wait] [<CommonParameters>]

The second parameter set can be used to skip the last part of the output:

Select-Object [[-Property] <Object[]>] [-ExcludeProperty <String[]>] [-ExpandProperty <String>] [-InputObject <PSObject>] [-SkipLast <Int32>] [-Unique] [<CommonParameters>]

The third parameter set can be used to specify an array of objects to return based on their index values:

Select-Object [-Index <Int32[]>] [-InputObject <PSObject>] [-Unique] [-Wait] [<CommonParameters>]

You can use Select as an alias for the Select-Object cmdlet.

The Get-VM cmdlet returns the Name, PowerState, NumCpu, and MemoryGB properties of the virtual machines by default. But what if you want to return the Name, VMHost, and Cluster properties instead? If you look at the properties of a virtual machine object, you will see the VMhost property. But you will not see a Cluster property. However, if you look at a VMHostImpl object, you will find a Parent property. The Parent property of a VMhostImpl object contains the cluster that the host is a member of.

Note

You can use this information to create a PowerCLI one-liner to get the host and cluster of all of the virtual machines:

PowerCLI C:> Get-VM | Select-Object -Property
    Name,VMHost, 
    @{Name="Cluster";Expression={$_.VMHost.Parent}}
Name VMHost        Cluster
---- ------        -------
DC1  192.168.0.133 Cluster01

The preceding command uses the Select-Object cmdlet to select the Name and VMHost properties of the virtual machine objects, and it creates a calculated property named Cluster that retrieves the cluster via the VMHost.Parent property.

Note

You can create a one-liner from all of your PowerShell scripts by using the semicolon as a separator between the commands. Use this only on the command line. It makes your scripts hard to read.

You can use the Select-Object -First parameter to specify the number of objects to select from the beginning of an array of input objects. For example, to retrieve the first three host types, use the following command:

PowerCLI C:> Get-VMHost | Select-Object -First 3

If you are typing commands at the pipeline, you can also use their aliases. For Select-Object, the alias is Select. So, the next example will give the same result as the preceding one:

PowerCLI C:> Get-VMHost | Select -First 3

To select a number of objects starting from the end of an array of objects, use the Select-Object -Last parameter. The following command retrieves the last cluster:

PowerCLI C:> Get-Cluster | Select-Object -Last 1

You can also skip objects from the beginning or the end of an array using the Select-Object -Skip parameter. The following command returns all of the folder objects except the first two:

PowerCLI C:> Get-Folder | Select-Object -Skip 2

Tip

A very interesting parameter of the Select-Object cmdlet is the -ExpandProperty parameter. You can use this parameter to expand the object if the property contains an object. For example, if you want to get the VMHostImpl object of the virtual machine named dc1, you can execute the following command:

PowerCLI C:> Get-VM -Name dc1 | Select-Object
    -ExpandProperty VMHost

Using the Where-Object cmdlet

If you only want a subset of all of the objects that a command returns, you can use the Where-Object cmdlet to filter the output of a command and only return the objects that match the criteria of the filter.

The Where-Object cmdlet syntax definition is so long that it'll take too much space in this book. You can easily get the Where-Object cmdlet syntax with the following command:

PowerCLI C:> Get-Help Where-Object

PowerShell V3 introduced a new, easier syntax for the Where-Object cmdlet. I will show you both the V2 and V3 syntaxes. First, let's see the new PowerShell V3 syntax.

Let's try to find all virtual machines that have only one virtual CPU. You can do this by searching for virtual machines that have a NumCPU property with a value of 1:

PowerCLI C:> Get-VM | Where-Object NumCpu -eq 1
Name   PowerState  Num CPUs  MemoryGB
----   ----------  --------  --------
DC1    PoweredOff  1         0.250

If you use the alias Where, the command looks more like a natural language:

PowerCLI C:> Get-VM | Where NumCpu -eq 1

You can also use the alias ? if you want to type less on the command line:

PowerCLI C:> Get-VM | ? NumCpu -eq 1

The PowerShell V2 syntax is a bit more obscure. You have to use a script block as the value of the Where-Object -FilterScript parameter:

PowerCLI C:> Get-VM | Where-Object -FilterScript {$_.NumCpu -eq 1}

Because the -FilterScript parameter is the first positional parameter of the Where-Object cmdlet, nobody uses the parameter name, and you will always see one of the following command lines being used:

PowerCLI C:> Get-VM | Where-Object {$_.NumCpu -eq 1}
PowerCLI C:> Get-VM | where {$_.NumCpu -eq 1}

The advantage of the PowerShell V2 syntax over the V3 syntax is that you can create complex filtering scripts. For example:

PowerCLI C:> Get-VM |
>> Where-Object {$_.NumCpu -gt 2 -and $_.MemoryGB -lt 16}
>>

The preceding command will show you all of the virtual machines with more than two virtual CPUs and less than 16 GB of memory. If you want to create the same filter using the PowerShell V3 syntax, you have to use two filters: one for the number of CPUs and one for the memory:

PowerCLI C:> Get-VM | Where NumCpu -gt 2 | Where MemoryGB -lt 16

Using the ForEach-Object cmdlet

Some cmdlets don't accept properties from the pipeline. On the other hand, you would like to use a cmdlet in the pipeline, but the property you want to use in the pipeline doesn't accept pipeline input. This is where the PowerShell ForEach-Object cmdlet will help you.

The ForEach-Object cmdlet has the following syntax. The first parameter set is for manipulating properties of the input objects:

ForEach-Object [-MemberName] <String> [-ArgumentList <Object[]>] [-Confirm] [-InputObject <PSObject>] [-WhatIf] [<CommonParameters>]

The -MemberName parameter is required.

The second parameter set is for processing script blocks for each object in the input:

ForEach-Object [-Process] <ScriptBlock[]> [-Begin <ScriptBlock>] [-Confirm] [-End <ScriptBlock>] [-InputObject <PSObject>] [-RemainingScripts <ScriptBlock[]>] [-WhatIf] [<CommonParameters>]

The -Process parameter is required.

The default first parameter is -Process, and that parameter name is most of the time omitted when using the cmdlet. The -Process parameter has a scriptblock as its parameter value, and this scriptblock will run for every object that passes the pipeline. For example:

PowerCLI C:> Get-VM | ForEach-Object {$_.Name}

The preceding command will retrieve the names of all of your virtual machines. In the scriptblock, the special variable $_ is used. The $_ variable is the current object that passes through the pipeline. So, $_.Name will return the value of the name property of the current object.

You can also use the alias foreach:

PowerCLI C:> Get-VM | foreach {$_.Name}

In PowerShell V3, the command is even simpler:

PowerCLI C:> Get-VM | foreach Name

If you want the ForEach-Object cmdlet to execute code before the objects start to pass through the pipeline, for example, to initialize a variable, you can create a scriptblock and use it as an argument value for the -Begin parameter. If you want the ForEach-Object cmdlet to execute code after the objects finish passing through the pipeline, for example, to return a result of a calculation you did on all of the objects in the pipeline, you can create a scriptblock and use it as an argument value for the -End parameter. For example:

PowerCLI C:> 1,2,3,4 |
>> ForEach-Object -Begin {"Start of the Script"; $Sum = 0} `
>> -Process {$Sum += $_} -End {"Sum of the elements: $Sum"}
>>
Start of the Script
Sum of the elements: 10

The preceding example was just to demonstrate the ForEach-Object cmdlet. If you want to take the sum of the objects in the pipeline, it is better to use the Measure-Object cmdlet that will be discussed in one of the following sections.

Note

In the example, you can see that the semicolon character is used to separate PowerShell commands. The backtick character (`) used as the last character of a line is used to escape the newline character and treat the newline character as a space. This enables you to break long lines of code and continue them on the next line.

To specify 1, 2, 3, 4, you can also use the PowerShell range operator (..):

1..4

The preceding operator is equivalent to the following:

1, 2, 3, 4

The ForEach-Object -Process scriptblock is run at least once even if the input object is $null, as you can see in the following example:

PowerCLI C:> $null | ForEach-Object -Process {"Hello world."}
Hello world.

You probably don't want to return anything if the input object is $null. You can solve this problem by testing inside the scriptblock if the input object exists with if ($_):

PowerCLI C:> $null | ForEach-Object -Process {if ($_) {"Hello."}}

Using the Sort-Object cmdlet

PowerCLI returns objects in a random order. If you want the objects to be sorted, you can use the Sort-Object cmdlet to sort them.

The Sort-Object cmdlet has the following syntax:

Sort-Object [[-Property] <Object[]>] [-CaseSensitive] [-Culture <String>] [-Descending] [-InputObject <PSObject>] [-Unique] [<CommonParameters>]

The Sort-Object cmdlet sorts objects in ascending or descending order based on the values of the properties of the object.

You can specify a single property or multiple properties (for a multi-key sort), and you can select a case-sensitive or case-insensitive sort. You can also direct Sort-Object to display only the objects with a unique value for a particular property.

The following example will give a list of all of your virtual machines, and their hosts sorted in ascending order on the hostname and the virtual machine name:

PowerCLI C:> Get-VM | Select-Object -Property VMHost,Name |
>> Sort-Object -Property VMHost,Name
>>

Using the aliases select for Select-Object and sort for Sort-Object and also using positional parameters, the preceding example can be shortened into:

PowerCLI C:> Get-VM | select VMHost,Name | sort VMHost,Name

Using the Measure-Object cmdlet

If you want to count objects or calculate the minimum, maximum, sum, and average of the numeric values of properties, you can use the Measure-Object cmdlet. For text objects, it can count and calculate the number of lines, words, and characters.

The Measure-Object cmdlet has the following syntax. The first parameter set is for counting the input objects and displaying the minimum, and maximum values, the sum, and average values of the input objects:

Measure-Object [[-Property] <String[]>] [-Average] [-InputObject <PSObject>] [-Maximum] [-Minimum] [-Sum] [<CommonParameters>]

The second parameter set is for counting characters, lines, and words in the input objects:

Measure-Object [[-Property] <String[]>] [-Character] [-IgnoreWhiteSpace] [-InputObject <PSObject>] [-Line] [-Word] [<CommonParameters>]

There are no required parameters.

Let's get back to our example from the ForEach-Object cmdlet where we counted the sum of the numbers 1, 2, 3, and 4. You can do this in an easier way using the Measure-Object cmdlet with the following command:

PowerCLI C:> (1..4 | Measure-Object -Sum).Sum
10

The only output property that the Measure-Object cmdlet fills by default is the Count property. To count the number of virtual machines in your environment, type the following command:

PowerCLI C:> Get-VM | Measure-Object


    Count    : 12
Average  :
Sum      :
Maximum  :
Minimum  :
Property :

If you just want the count value, you can specify the Count property:

PowerCLI C:> (Get-VM | Measure-Object).Count
12

Otherwise, you can use the Select-Object -ExpandProperty parameter as follows:

PowerCLI C:> Get-VM | Measure-Object |
>> Select-Object -ExpandProperty Count
>>
12

You can also use the alias measure for Measure-Object:

PowerCLI C:> (Get-VM | measure).Count
12

Note

To get the average, sum, maximum, and minimum values of a property, you have to specify the property name and the parameters for the values that you want to retrieve.

The following command will retrieve the average, sum, maximum, and minimum values of the ProvisionedSpaceGB property of all of your virtual machines:

PowerCLI C:> Get-VM | Measure-Object -Property
    ProvisionedSpaceGB -Average -Sum -Maximum -Minimum


    Count    : 12
Average  : 60.590376389601
Sum      : 727.084516675211
Maximum  : 221.090891393833
Minimum  : 2.58988594077528
Property : ProvisionedSpaceGB

To count the number of characters, words, and lines in a string, you can use the -Line, -Word, and -Character parameters:

PowerCLI C:> "Learning PowerCLI" |
>> Measure-Object -Line -Word -Character
>>


               Lines            Words       Characters Property
           -----            -----       ---------- --------
               1                2               17

You can also use the Measure-Object cmdlet to count the number of lines, words, and characters in the here-string:

PowerCLI C:> @"
>> Every vSphere admin should
>> Learn PowerCLI!
>> "@ | Measure-Object -Line -Word -Character
>>


               Lines            Words       Characters Property
           -----            -----       ---------- --------
               2                6               42

Rounding a value

If you don't want a value to have several fractional digits, you can use the .NET Math.Round method to round a value to the nearest integer or the specified number of fractional digits:

  • The first parameter of the Math.Round method is the value that you want to round
  • The optional second parameter is the number of fractional digits that you want the value to round to

If you don't specify the second parameter, the value will be rounded to the nearest integer. For example:

PowerCLI C:> [math]::Round(60.590376389601,2)
60.59

You can use the Math.Round method in a calculated property. For example:

PowerCLI C:> Get-VM | Measure-Object -Property
    ProvisionedSpaceGB -Average -Sum -Maximum -Minimum |


    >> Select-Object -Property Count,
>> @{Name="Average";Expression={[math]::Round($_.Average,2)}}
>>


    Count        Average
-----        -------
   12          60.59

Using the Group-Object cmdlet

The Group-Object cmdlet group's objects contain the same value for the specified properties. Using the Group-Object cmdlet can be very useful, for example, when you want to count the number of instances of a specific value of a property.

The Group-Object cmdlet has the following syntax:

Group-Object [[-Property] <Object[]>] [-AsHashTable] [-AsString] [-CaseSensitive] [-Culture <String>] [-InputObject <PSObject>] [-NoElement] [<CommonParameters>]

Let's create a PowerCLI command to count the number of instances of each operating system installed on a virtual machine. In a traditional scripting language, you would have to loop through all of your virtual machines and increment counters for each operating system. In PowerCLI, you can achieve this much easier using the Group-Object cmdlet. The name of the guest operating system is in a virtual machine's Guest.OSFullName property. You can use the Group-Object cmdlet to group the objects on the Guest.OSFullName property using a calculated property. The Group-Object cmdlet will return the Count, Name, and Group properties by default. Using the -NoElement parameter will remove the Group property from the output. The following example groups the virtual machines on the Guest.OSFullname property and returns the Count and Name properties for each Guest.OSFullName:

PowerCLI C:> Get-VM |
>> Group-Object -Property @{Expression=
    {$_.Guest.OSFullName}} -NoElement  |
>> Format-Table -AutoSize
>>


    Count Name
----- ----
    1 Microsoft Windows Server 2012 (64-bit)
    1 SUSE Linux Enterprise 11 (32-bit)
    3 SUSE Linux Enterprise 11 (64-bit)
    1
    2 Microsoft Windows Server 2008 R2 (64-bit)
    1 CentOS 4/5/6 (32-bit)
    2 Other (64-bit)
    1 CentOS 4/5/6 (64-bit)
    1 CentOS 4/5/6 (64-bit)

Note

The one virtual machine that does not have a guest operating system name is powered off for a long time. The guest operating system is determined using the VMware Tools. VMware vSphere can't find the guest operating system for this virtual machine while it is powered off.

The Format-Table -AutoSize command formats the output, so that you will get the full operating system name.

Using the Compare-Object cmdlet

If you want to compare two objects or sets of objects, you have to use the Compare-Object cmdlet.

The Compare-Object cmdlet has the following syntax:

Compare-Object [-ReferenceObject] <PSObject[]> [-DifferenceObject] <PSObject[]> [-CaseSensitive] [-Culture <String>] [-ExcludeDifferent] [-IncludeEqual] [-PassThru] [-Property <Object[]>] [-SyncWindow <Int32>] [<CommonParameters>]

From the sets of objects that the Compare-Object cmdlet compares one set of objects is named the reference set, and the other set is named the difference set.

Let's compare two strings:

PowerCLI C:> $string1 = "Learning PowerCLI"
PowerCLI C:> $string2 = "Learning PowerCLI!"
PowerCLI C:> Compare-Object -ReferenceObject $string1 `
>> -DifferenceObject $string2
>>
InputObject                       SideIndicator
-----------                       -------------
Learning PowerCLI!                =>
Learning PowerCLI                 <=

The output shows that the strings are not the same. The <= symbol indicates objects from the reference set. The => symbol indicates objects from the difference set. If you use the -IncludeEqual parameter, the Compare-Object cmdlet will also show objects that are equal in both sets. These objects are indicated by the == symbol.

Using the Tee-Object cmdlet

The Tee-Object cmdlet saves the command output in a file or a variable and also sends it down the pipeline. If Tee-Object is the last command in the pipeline, the command output is displayed at the prompt.

The Tee-Object cmdlet has the following syntax. The first parameter set is for saving the output in a file:

    Tee-Object [-FilePath] <String> [-Append] [-InputObject <PSObject>]
    [<CommonParameters>]

The -FilePath parameter is required. The second parameter set is for saving the output in a file using a literal path:

Tee-Object [-InputObject <PSObject>] -LiteralPath <String>
    [<CommonParameters>]

The -LiteralPath parameter is required. The third parameter set is for saving the output in a variable:

Tee-Object [-InputObject <PSObject>] -Variable <String>
    [<CommonParameters>]

The -Variable parameter is required.

The following example retrieves all of your virtual machines and saves the virtual machine objects in a variable named VMs. It also sends the objects down the pipeline and displays the Name and PowerState properties of the virtual machines:

PowerCLI C:> Get-VM | Tee-Object -Variable VMs |
>> Select-Object -Property Name,PowerState
>>

The following figure shows that the Tee-Object cmdlet writes its output to the variable $VMs and pipes its output to the Select-Object cmdlet in the pipeline:

Using the Tee-Object cmdlet

The Tee-Object cmdlet is named after the T-splitter used in plumbing. Doesn't the Tee-Object cmdlet in the figure look like a T-splitter?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.125.219