Tahir Hassan
Tahir Hassan

Reputation: 5817

PowerShell: $input value changes in function

What I have found is that when I write the following function:

function test {
    Write-Host ($input | Measure-Object).Count
    Write-Host ($input | Measure-Object).Count
}

with sample input:

dir | test

it writes on the console:

18
0

I think it is because the first pipe to Measure-Object overwrites $input. I know of a workaround where I would make a new array and pass that around:

function test {
    $inp = @($input)
    Write-Host ($inp | Measure-Object).Count
    Write-Host ($inp | Measure-Object).Count
}

However I don't like it because I am introducing a new variable. Is there a way of piping to a cmdlet while leaving $input unaffected?

Upvotes: 1

Views: 474

Answers (2)

Roger Lipscombe
Roger Lipscombe

Reputation: 91835

$input is an ArrayListEnumeratorSimple:

C:\Users\roger> $input.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
False    True     ArrayListEnumeratorSimple                System.Object

...which means that it's an enumerator over a sequence of items. Thus, as you consume items in it, you use them up.

I attempted the following:

function foo
{
    $input | select -first 3 | % { Write-Host -ForegroundColor 'Red' $_ }
    $input | % { Write-Host -ForegroundColor 'White' $_ }
}

...to show that select -first 3 eats the first 3 items, but it appears to swallow all of them.

Trying the following:

function bar
{
    $n = 0
    foreach ($x in $input) {
        if ( ++$n -eq 3 ) { break }
        Write-Host -ForegroundColor 'Red' $x
    }

    $input | % { Write-Host -ForegroundColor 'White' $_ }
}

dir | bar

...shows the difference.

However, since $input is an enumerator (strictly an IEnumerator), you can call Reset() on it to rewind it.

Note that in .NET-land, not all enumerators can be reset. I'm not sure if there are any scenarios in PowerShell where this is the case with $input.

Upvotes: 2

CB.
CB.

Reputation: 60918

Try this:

function test {    
 Write-Host ($input | Measure-Object).Count
 $input.reset()
 Write-Host ($input | Measure-Object).Count
}

reading about $input enumerator

Upvotes: 2

Related Questions