Search code examples
powershellfunction

without using the pipeline, values to array parameter are being treated as multi line string


Function foo{
    [CmdletBinding()]
    Param(
    [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [array]$path
    #[string[]]$path    #I tried this too, same issue as above.
    )

    Begin{"---begin---" ; $path}
    Process{"---Process---" ; $path}
    End{"---End---" ; $path}
    }

without the pipeline, multiple values passed to the path parameter are always seen as a multi line string, foo -path 'C:\temp\green', 'C:\temp\blue', 'C:\temp\red':

---begin---
red
blue
green
---Process---
red
blue
green
---End---
red
blue
green

with the pipeline, values to path are correctly treated as array elements, foo -path 'red', 'blue', 'green':

---begin---
---Process---
red
---Process---
blue
---Process---
green
---End---
green

I dont understand this sudden change of behaviour, I am expect both instances of invoking foo (with or without pipeline) to output values to path as single array elements.

win11/pwsh 7.4


Solution

  • The process block is invoked per each value from pipeline, each item is passed one by one and processed. That's not the case when you bind the array to your parameter. If you want to handle both cases equally, binding from pipeline and parameter binding, you will need a loop over your parameter. See also process from about Functions Advanced Methods.

    Function foo {
        [CmdletBinding()]
        Param(
            [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
            [array] $path
        )
    
        Begin {
            '---begin---' ; $path
        }
        Process {
            foreach ($item in $path) {
                '---Process---' ; $item
            }
        }
        End {
            '---End---' ; $path
        }
    }
    

    As an aside, values are not treated as a multi-line string when not using the pipeline, they're always treated as what the parameter is typed to, an array in this case. You will always need a loop, be it from the pipeline or not.

    function foo {
        [CmdletBinding()]
        Param(
            [Parameter(ValueFromPipeline)]
            [array] $path
        )
    
        Process {
            $path.GetType()
        }
    }
    
    foo 1, 2, 3
    1, 2, 3 | foo