powershell Get-ChildItem result in array

Question:

(Get-ChildItem -File -Recurse -Path $path).Fullname returns array of full names
(Get-ChildItem -File -Recurse -Path $path).Name returns array of files names
but
(Get-ChildItem -File -Recurse -Path $path).Length returns only one value – the count of elements

Question – how to get result as array of file lengths ?

Answer:

To complement Mathias R. Jessen’s helpful answer:

tl;dr

Use of the .ForEach() array method enables a concise and performant solution:


As pointed out in Mathias’ answer, type-native properties – such as .Length on array instances – take precedence over the so-called member-access enumeration that you tried to perform – that is, you wanted to collect the .Length property values of the elements of your collection (array; the System.IO.FileInfo instances output by Get-ChildItem), and return them as an ([object[]]) array.

  • GitHub issue #7445 discusses this situational ambiguity and proposes introducing a dedicated operator, say %. so that you can unambiguously request either regular property access or member-access enumeration.

A perhaps surprising aspect of member-access enumeration is that it applies pipeline logic in that it situationally returns a scalar, namely if the collection happens to contain just one element.

  • E.g., @(Get-Date).Year.GetType().Name returns an System.Int32, not Object[], indicating that an integer rather than a (single-element) array containing an integer was returned.
  • GitHub issue #6802 discusses this.

Member-access enumeration is not only convenient, but also fast, because it avoids looping / enumeration in PowerShell code.

Use of the ForEach-Object or Select-Object cmdlets, as shown in Mathias’ answer, is definitely a functional but slow workaround for not being able to use member-access enumeration in a given situation, due to use of the pipeline, which isn’t necessary for input that that is already in memory in full.

Therefore, use of the .ForEach() array method – using the overload where you simply specify the target property name ('Length') – is a concise and better-performing alternative.

  • Note: Unlike with member-access enumeration, the return value from .ForEach() is always a collection, albeit not an array: it is of type [System.Collections.ObjectModel.Collection[psobject]], which, however, will behave like an array in most contexts.[1]

[1] Unlike an array, this type of collection is extensible (you can add or remove elements). Due to the element type being [psobject], each element is typically invisibly wrapped in this type; e.g., 42 -is [psobject] is $false, but @(42).ForEach({ $_ })[0] -is [psobject] is $true. Unfortunately, there are cases where this near-invisible wrapper results in different behavior – see GitHub issue #5579.

Source:

powershell Get-ChildItem result in array by licensed under CC BY-SA | With most appropriate answer!

Leave a Reply