Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Powershell piping multiple PSCustomObjects drops all but first object

I’m making some modules to make RESTAPI calls easier for our software (since all resources use different logic to how I can find them and how they should be called but that’s a separate story). I’m making Get-, Set-, New-, and Remove- for each resource and just found that you can’t pipe more than one object to modules that takes arrays from the pipeline. Here’s an illustration of the problem that you can copy-paste into your environment:

function Get-MyTest {

    param(
        [string[]]$MyInput
    )


    [array]$Output = @()
    $i=0

    foreach($Item in $MyInput){

        $i++

        $Output += [pscustomobject]@{
            Name = $Item
            Id = $i
        }

    }

    return $Output

}

function Get-IncorrectResults {

    param(
        [parameter(ValueFromPipeline)][array]$MyIncorrectInput
    )

    foreach ($Item in $MyIncorrectInput) {
        
        Write-Host "Current object: $Item `n "

    }

}

The Get module can return more than one object. Each object returned is a PSCustomObject, so if there are more than one returned it becomes an array of PSCustomObjects. Here’s the problem:

This works:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

$Results = Get-MyTest -MyInput "Test1","Test2","Test3"
Get-IncorrectResults -MyIncorrectInput $Results

This only returns the first item:

$Results = Get-MyTest -MyInput "Test1","Test2","Test3"
$Results | Get-IncorrectResults

If the Get part returns more than one object, only the first object is passed on to the Remove-MyModule. I tried changing the parameter definition from [pscustomobject[]] to [array] but it’s the same result. What is the reason for dropping all but the first array item when piping but not when using it as a parameter?

>Solution :

The structure of an advanced PowerShell function is as follows:

function Function-Name {
  param(
    <# parameter definitions go here#>
  )

  begin {
    <# this runs once when the pipeline starts #>
  }

  process {
    <# this runs once for every input item piped to the function #>
  }

  end {
    <# this runs once at the end of the pipeline #>
  }
}

When you omit the begin/process/end blocks, PowerShell assumes your function body is really the end block – so this function definition:

function Function-Name {
  param()

  Do-Something
}

… is the exact same as:

function Function-Name {
  param()

  begin {}

  process {}

  end {Do-Something}
}

Notice that the process block – the only piece of the function body that repeats with new input – is assumed empty, and the Do-Something statement will not be executed until after the last input item has been received.

This is why it looks like it "drops" everything but the last input object.

Place the code that consumes the pipeline-bound variable inside the process block and it’ll work:

Remove-MyModule{

    param(
        [parameter(ValueFromPipeline)][pscustomobject[]]$MyModules
    )

    process {
        foreach($Module in $MyModules){
            Invoke-RestMethod -Method Delete -Uri "MyURL" -Body (ConvertTo-Json $Module) -UseDefaultCredentials
        }
    }
}

For more information about the syntax and semantics of advanced functions, see the about_Functions_Advanced_Methods help file

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading