简体   繁体   中英

How to get a list of a particular field from a list of objects in powershell

I am new to powershell scripting. Apologies if I am missing something simple.

Let's say I have an object called object that has a field called field . Now let there be a list of these objects.

How would I get the list of fields in the same order?

In python it would be:

list_of_objects = [o1, o2, o3]
list_of_fields = [i.field for i in list_of_object]

is nice, and not so nice, because it unwraps collections for you, and sometimes this can hide that it is masking the elements' members. When you're using $parents.item , you're accessing the array's method, and trying to access its members (which there aren't any, so is giving you $null ):

Item           ParameterizedProperty System.Object IList.Item(int index) {get;set;}

You can overcome this by using the method I shared in the comments to iterate over each member and avoid this masking:

$list = $parents | ForEach-Object -MemberName item
$list.registration.parentCompoundNumber

Alternatively, a syntax more people are familiar with:

$list = $parents | Select-Object -ExpandProperty item

or unrolling it yourself:

# you could directly assign the outputs of a `foreach` loop to a variable by
# removing these comments (<##>)
<# $items = #> 
  foreach ($parent in $parents) {
    $parent.item.registration.parentCompoundNumber
  }

To see when this masking is happening, consider this example which uses the unary array operator:

, @('a', 'b', 'c') | Get-Member

This will let you observe the wrapping array or collection's members.

To complement TheIncorrigible1's helpful answer :

The linked answer contains viable workarounds for the member-name collisions; let me add a PSv4+ alternative that is both more concise and faster than a pipeline-based approach:

$parent.ForEach('item').registration.parentCompoundNumber

Using the .ForEach() array method with a property name ( 'item' ) unambiguously targets the elements ' members.


To offer a slight reframing of the explanation for why a workaround is needed:

  • PowerShell's member enumeration essentially treats $someCollection.someProp as if you had written foreach ($element in $someCollection) { $element.someProp } ; that is, the elements of $someCollection are enumerated, and the the elements' .someProp property values are returned as an array.

    • Note: As in the pipeline, if the collection happens to have just one element, that element's property value is returned as-is , not as a single-element array.
  • However, if the collection type itself happens to have a member named someProp , it is used, and no enumeration takes place; that is, collection-level members shadow (take precedence over) element-level members of the same name - and that is what happened with .Item in your case.

    • When in doubt, output $someCollection.someProp interactively / during debugging to see what it evaluates to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM