windowspowershellpowershell-cmdletselect-object

How select-object cmdlet accepts input by pipeline?


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.


Solution

  • 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.