In addition to the existing ones, useful answers indicating when to use which approach and performance comparison .
Outside the pipeline use:
$ objects . Name
(PSv3 +) as shown in rageandqq's answer , which is syntactically simpler and much faster .In the pipeline where the result should be processed further or the results do not fit into memory in general, use:
$ objects | Select-Object -ExpandProperty Name
- The need for
-ExpandProperty is explained in Scott Saad's answer . - You get the usual benefits of pipelining one at a time, which usually produces output right away and maintains constant memory usage (if you still don't collect the results in memory).
- Exchange :
- The use of the pipeline is relatively slow.
For small input collections (arrays), you probably won't notice the difference , and especially on the command line, sometimes the ability to type a command is easily more important.
Here is an easy-to-enter alternative , which, however, is the slowest approach ; it uses the simplified ForEach-Object syntax called the operation operator (again, PSv3 +) :; For example, the following PSv3 + solution is easy to add to an existing command:
$objects | % Name # short for: $objects | ForEach-Object -Process { $_.Name }
For the sake of completeness: a little-known method for collecting PSv4 + .ForEach() is another alternative :
# By property name (string): $objects.ForEach('Name')
This approach is similar to listing members with the same trade-offs, except that pipelining logic is not applied; it's a little slower , although still noticeably faster than the conveyor.
To extract a single property value by name (string argument), this solution is on par with the enumeration of members (although the latter is syntactically simpler).
The script block variant, although much slower, allows arbitrary transformations; it’s a faster “all in one memory” alternative to the pipeline-based ForEach-Object cmdlet .
Comparing the effectiveness of different approaches
Here are sample time intervals for various approaches based on an input collection of 100,000 objects averaged over 100 runs; absolute numbers are not important and vary depending on many factors, but they should give you an idea of relative effectiveness:
Command FriendlySecs (100-run avg.) Factor ------- --------------------------- ------ $objects.ForEach('Number') 0.078 1.00 $objects.Number 0.079 1.02 foreach($o in $objects) { $o.Number } 0.188 2.42 $objects | Select-Object -ExpandProperty Number 0.881 11.36 $objects.ForEach({ $_.Number }) 0.925 11.93 $objects | % { $_.Number } 1.564 20.16 $objects | % Number 2.974 38.35
A solution using a member / property-based data collection method is 10+ faster than the fastest pipeline-based solution.
The foreach solution is about 2.5 slower, but still about 4-5 times faster than the fastest pipelined solution.
Using a script block with a solution to the collection method ( .ForEach({... } ) significantly slows down the process, so it almost corresponds to the fastest pipeline-based solution ( Select-Object -ExpandProperty ).
Curiously, % Number ( ForEach-Object Number ) works worse, although % Number is the conceptual equivalent of % { $_.Number } ).
Source code for tests :
Note. To run these tests, load the Time-Command function from this list .
$count = 1e5
mklement0 Feb 20 '18 at 2:58 p.m. 2018-02-20 14:58
source share