Why do parentheses change the iterating type?

Viewed 69
PS > Get-Item env: | Select-Object -First 1 | ForEach-Object GetType

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

PS > (Get-Item env:) | Select-Object -First 1 | ForEach-Object GetType

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DictionaryEntry                          System.ValueType

Preamble: I was wondering why I cannot use Where-Object to filter Get-Item env:

P.S. Just in case, the solution to filter env:

  1. (Get-Item env:) | Where-Object Name -eq 'PUBLIC'
  2. Get-Item env:\* | Where-Object Name -eq 'PUBLIC'
  3. Get-ChildItem env: | Where-Object Name -eq 'PUBLIC'
  4. gi env: |% GetEnumerator |? Name -eq 'PUBLIC' (added after @santisq answer, he deleted it)

However despite of the fact thar Get-Item env: list all the env variables (however the documentation said it should not while * is not set pointed), you cannot filter Get-Item env: | Where-Object Name -eq 'PUBLIC because Get-Item env: | Measure-Object Count is 1

Environment: PSVersion 5.1.19041.610

1 Answers

Env is a PsDrive just like C, but with a different provider (Environment provider).

Get-Item returns just the item itself and not the item contents by default. It has the capability of returning the item contents. Using grouping operator () forces enumeration and runs the inner command to completion before sending anything through the pipeline.

Get-Item env: returns a single, unenumerated collection, which is why the count is 1. (Get-Item env:) enumerates the inner collection, which is why the count is greater than 1. If you want the items contained in a PsDrive, you should just use Get-ChildItem env:. Appending your path with \* instructs the command to return each single child item matched by *, which is the same as Get-ChildItem without the trailing \*. Only when the collection is enumerated can you apply filtering logic against the contained items.

# No enumeration
Get-Item -Path env: | Measure | Select -Expand Count
1
Get-Item -Path env: | Where Name -eq 'PUBLIC' # returns nothing

# Forced enumeration
(Get-Item -Path env:) | Measure | Select -Expand Count
44
(Get-Item -Path env:) | Where Name -eq 'PUBLIC'
Name                           Value
----                           -----
PUBLIC                         C:\Users\Public

# Implied enumeration by returning targeting child items
Get-Item -Path env:\* | Measure | Select -Expand Count
44

# returns child items of target
Get-ChildItem -Path env: | Measure | Select -Expand Count
44
Related