0

Sorry for asking a novice question, as I am learning Powershell and I am confused how select-object -property parameter works with pipeline. As mentioned in help it doesnot accept the value through pipeline.

For e.g: the below code should have given an error: get-process|select-object -property name,vm,pm

Can someone explain or guide me, thanks in advance.

  • If you carefully re-read the help - the parameter `-InputObject` accepts pipeline input. ;-) – Olaf May 10 '22 at 06:50
  • @Olaf i re-read the help document and I am still confused. Am I missing something? – sidharth negi May 10 '22 at 07:59
  • What confuses you? There's only one property accepting pipeline input and that's `-InputObject` – Olaf May 10 '22 at 08:12
  • @Olaf as you said there is only one parameter that is `-InputObject` that takes input through pipeline, then how does the `-Property` parameter work when it doesnot take any pipeline input. – sidharth negi May 10 '22 at 08:48
  • You specify the properties you want to select!? – Olaf May 10 '22 at 09:13
  • In your example, `name,vm,pm` are passed as _named parameter arguments_, not pipeline input. – Mathias R. Jessen May 10 '22 at 09:33
  • `Select-Object` gets its input object through the pipeline, from that object it selects the properties you specify. Does that make it clearer? – Theo May 10 '22 at 09:34
  • @Olaf Yes you are right we specify the properties we want. But what am saying is when we pipe two commands the Powershell use the process of **pipeline parameter binding** , which uses two methods **ByValue** and **ByPropertyname**. But the `-property`parameter didnot accept any pipeline input as mentioned in the help document. – sidharth negi May 10 '22 at 09:43
  • 1
    That's why you specify the properties you want to see on the command line by providing values for the parameter `-Property` for the cmdlet `Select-Object`. The objects passed by the pipeline will be taken by the the parameter `-InputObject` of the cmdlet `Select-Object` – Olaf May 10 '22 at 10:35
  • 1
    @sidharthnegi pipeline parameter binding is _not_ in play wrt `-Property` - try running `Trace-Command -Expression { "a string" |Select-Object -Property Length } -Name *Param* -PSHost` to see what actually happens – Mathias R. Jessen May 10 '22 at 11:09

1 Answers1

1

To better understand how Select-Object works, here is a very simplified demo function that works similar to Select-Object:

function Select-ObjectSimplified {
    [CmdletBinding()]
    param (
        # "ValueFromPipeline" means this parameter accepts pipeline input
        [Parameter(Mandatory, ValueFromPipeline)] [PSObject] $InputObject,

        # This parameter does NOT accept pipeline input
        [Parameter(Mandatory)] [Object[]] $Property
    )
    
    # The process section runs for each object passed through the pipeline.
    process {
        # Create an ordered hashtable that will store the names and values 
        # of the selected properties.
        $OutputObject = [ordered] @{}

        # Loop over each property of $InputObject
        foreach( $InputObjectProperty in $InputObject.PSObject.Properties ) {

            # Check if the current property is listed in -Property argument.
            if( $Property -contains $InputObjectProperty.Name ) {

                # Add the current property to the output object.
                $OutputObject[ $InputObjectProperty.Name ] = $InputObjectProperty.Value
            }
        }

        # Convert the hashtable to a PSCustomObject and (implicitly) output it.
        [PSCustomObject] $OutputObject
    }   
}

Demo:

# Create an array of two objects.
$example = [PSCustomObject]@{ Foo = 4;  Bar = 8  },
           [PSCustomObject]@{ Foo = 15; Bar = 16 }

# Pass the array as input to the pipeline.
$example | Select-ObjectSimplified -Property Foo | Format-List

Output:

Foo : 4

Foo : 15

Although the parameter -Property doesn't accept pipeline input, we can still use it when we process the pipeline input that binds to parameter -InputObject. There is no need for -Property to accept pipeline input, because it stays constant during the whole run of the pipeline.

The demo is executed by PowerShell like this:

$example | Select-ObjectSimplified -Property Foo | Format-List

  1. The argument "Foo" gets bound to parameter -Property. The parameter -InputObject is not bound yet, because we didn't explicitly pass an argument to it.
  2. The first element of the array $example is passed through the pipeline. The argument [PSCustomObject]@{ Foo = 4; Bar = 8 } gets bound to parameter $InputObject.
  3. The process{} section runs. There we can get the current pipeline object from $InputObject and get the argument of parameter -Property from $Property. So $InputObject will be different for each run of process{}, but $Property does not change, it is constant.
  4. The second element of the array $example is passed through the pipeline. The argument [PSCustomObject]@{ Foo = 15; Bar = 16 } gets bound to parameter $InputObject.
  5. Like 3), but with different value for $InputObject.

Hope that shed some light on the topic. To get an even better understanding I suggest to read About Pipelines and then follow a tutorial to write your own pipeline function. The concept only did really click for me, once I successfully wrote my first real pipeline functions.

zett42
  • 25,437
  • 3
  • 35
  • 72