0

Is this question about "[System.Collections.Generic.List[string]] as return value" I got an interesting answer from @Ash about using $PSCmdlet.WriteObject() instead of Return to avoid pipeline pollution. And it seemed to work in that context. However, in trying to explain this to someone, I made this little example, using an ArrayList instead, since I know that pollutes the pipeline every time. And here it does NOT work. Without the ArrayList lines, both return a type of [System.String]. With those lines they BOTH return [System.Object]. And if I prefix the ArrayList line with [Void] to redirect the pollution, it's back to [System.String]. I have verified that in both failure cases the .Count of the returned object is 2. Which got me thinking, is this only a solution for the unroll problem? So I revised the test to use a System.Collections.Generic.List[string] for the return, and I find that without the ArrayList to pollute, WriteObject works, while return only works with the unroll fix, i.e. return ,$return. Add the pollution back in, and they both get polluted. So, was my understanding wrong, and this solution is only applicable to the unroll problem? And if so, is there anything specific to recommend one approach over the other? And, IS THERE a real solution to the pipeline pollution problem with functions? Or is this just how functions work, and the answer is to use classes where you have complete control over return types, and PowerShell doesn't pour it's effluent into your variables willy nilly?

function ReturnObject () {
    [String]$return = 'Return a string'
    (New-Object System.Collections.ArrayList).Add('Pollution')

    return $return
}

function WriteObject {
    [CmdletBinding()]
    param ()
    [String]$writeObject = 'Writeobject a string'
    (New-Object System.Collections.ArrayList).Add('Pollution')

    $PSCmdlet.WriteObject($writeObject)
}

CLS
$Returned = ReturnObject
Write-Host "$Returned ($($Returned.GetType().FullName))"

$Written = WriteObject
Write-Host "$Written ($($Written.GetType().FullName))"

And the Generic.List variant

function ReturnObject () {
    $return = New-Object System.Collections.Generic.List[string]
    $return.Add('Return a List')
    (New-Object System.Collections.ArrayList).Add('Pollution')

    return ,$return
}

function WriteObject {
    [CmdletBinding()]
    param ()
    $writeObject = New-Object System.Collections.Generic.List[string]
    $writeObject.Add('Writeobject a List')
    (New-Object System.Collections.ArrayList).Add('Pollution')

    $PSCmdlet.WriteObject($writeObject)
}

CLS
$Returned = ReturnObject
Write-Host "($($Returned.GetType().FullName)) $($Returned.Count)"

$Written = WriteObject
Write-Host "($($Written.GetType().FullName)) $($Returned.Count)"
Gordon
  • 6,257
  • 6
  • 36
  • 89
  • Why don't you go for the [**accepted**](https://stackoverflow.com/a/67627137/1701026) solution? The [**Unary Comma**](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_operators#comma-operator-), see also: [Why is a leading comma required when creating an array?](https://stackoverflow.com/a/42772846/1701026). – iRon May 27 '21 at 10:00
  • 1
    With regards to "*polluting*" the pipeline: you don't need to [`Write-Output`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/write-output) or any other command to put something on ("pollute") the pipeline. Meaning if you don't capture the results of a command/method (read: assign the results from a command to a variable -including `$Null = ...`-, see also: [`ArrayList.Add` method which always returns the index of the new item that you add](https://stackoverflow.com/a/28034668/1701026)), it will simply be put on the pipeline. – iRon May 27 '21 at 10:06
  • @iron The comma works for that specific issue of unrolled single member arrays, but not for pipeline pollution in general. So I guess that is my question, is there any means to get PowerShell to NOT crap in the pipeline? As it is we have to constantly review every cmdlet and .NET approach to see if it does or doesn't, and then mitigate. Would be nice to just turn that "feature" off. The only way to do that seems to be to never use Functions. Which given that classes are not yet 100% implemented, seems like a big failure on Microsoft's part. – Gordon May 27 '21 at 10:57
  • I really do not see what you mean by _"pollution"_.. Some PowerShell cmdlets and .Net functions emit output, others do not. It's just a question of whether you want to do something with that output or not, because you can always capture the output in a variable (or `$null` or prepend `[void]` to a .Net method) and ignore it. That way it will not "pollute" the pipeline as you put it. Simply look up the function or cmdlet you are aiming to use and check if it has output or not. – Theo May 27 '21 at 13:08
  • I guess I just see it as something I NEVER want. I don't want to have to verify which ones need coddling and which don't. To my mind, unless you are actually using the pipeline with `|` nothing should ever change the value of a variable without use of `=`, and `return $Variable` should return that variable and nothing more, unless I specifically tell the function to crap in the pipeline. At a minimum, there should be an option, perhaps not the default, but an option, to force that behavior script wide. But I guess the answer really is "Use Classes", which I want to do for other reasons too. :) – Gordon May 27 '21 at 18:09
  • I have created a PowerShell request for this issue: [**`#15781`** Strict `Write-Output`](https://github.com/PowerShell/PowerShell/issues/15781) – iRon Jul 15 '21 at 16:46

0 Answers0