26

The scenario: I'm using Select-Object to access properties of a piped object, and one of those properties is itself an object. Let's call it PropertyObject. I want to access a property of that PropertyObject, say Property1. Is there any nice and clean way of accessing Property1, along the lines of:

...| select-object PropertyObject.Property1

While experimenting I can only get it to work if I do something like:

...| select-object {$_.PropertyObject.Property1}

and if I want to display it with a decent column name it gets even messier:

...| select-object @{Name="Property1"; Expression={$_.PropertyObject.Property1}}

Given how clean and concise PowerShell is in general, I can't help thinking I'm missing something and there should be a cleaner way of accessing a property of a property. Is there?

EDIT: As requested by Matt, here is the concrete example:

I'm reading an XML file, Books3.xml:

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date inprint="false">2000-10-01</publish_date>
      <description>An in-depth look at creating applications 
      with XML.</description>
      <publisher>
        <name>Simon and Schuster</name>
        <country>USA</country>
        <city>New York</city>
      </publisher>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date inprint="true">2000-12-16</publish_date>
      <description>A former architect battles corporate zombies, 
      an evil sorceress, and her own childhood to become queen 
      of the world.</description>
      <publisher>
        <name>HarperCollins</name>
        <country>USA</country>
        <city>New York</city>
      </publisher>
   </book>
   <book id="bk103">
      <author>Corets, Eva</author>
      <title>Maeve Ascendant</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date inprint="false">2000-11-17</publish_date>
      <description>After the collapse of a nanotechnology 
      society in England, the young survivors lay the 
      foundation for a new society.</description>
      <publisher>
        <name>Macmillan</name>
        <country>United Kingdom</country>
        <city>London</city>
      </publisher>
   </book>
</catalog>

Code to load XML into XmlDocument:

$filePath = "C:\Temp\books3.xml"
$xmlDoc = new-object xml
$xmlDoc.load($filePath)

Attempting to read details for each book:

$xmlDoc.catalog.book | select author, title, publisher.name

Result:

author                     title                      publisher.name
------                     -----                      --------------
Gambardella, Matthew       XML Developer's Guide
Ralls, Kim                 Midnight Rain
Corets, Eva                Maeve Ascendant
2
  • 1
    What is your powershell version? If its 3.0 you can just $object.PropertyObject.Property1 else you would just chain the selects select PropertyObject | select Property1. You might need some expands in there but that is the jist. It all depends on the props Commented Apr 12, 2015 at 23:20
  • I made a minor update but I don't think it is the answer you are looking for. Extracting a single property is easier than the object output you are looking for. Select is the way to go for this. You could clean it up by moving the hash to a single variable but it does not change the code needed. Commented Apr 13, 2015 at 3:33

3 Answers 3

57

You can use calculated properties. A short form would allow for this:

$xmlDoc.catalog.book | select author, title, {$_.publisher.name}

If the property names are important you need to add them in.

$xmlDoc.catalog.book | select author, title, @{N="PublisherName";E={$_.publisher.name}}

Where N is short for name and E is short for expression.

Sign up to request clarification or add additional context in comments.

1 Comment

This actually answers OP's question.
9

It would be easier if you had something actual repeatable for us to test but we can fake that with Get-Items return.

(Get-Item C:\temp\logoutput).Parent.Name

.Parent is actually a System.IO.DirectoryInfo object. I use PowerShell 3.0 dot notation to get the name of the parent

The same result can be acquired by chaining the select calls

Get-Item C:\temp\logoutput | select -expand Parent | Select -Expand name

This of course would work in PowerShell 2.0 but is not a terse and the 3.0 version.

Post Question Edit

Not sure what you are hoping for. What you have does work at extracting sub properties the way you have it. I can only offer an alternate approach that might be more intuitive and friendly but the result is the same.

$xml.catalog.book | ForEach-Object{
    $_ | Add-Member NoteProperty "PublisherName" $_.publisher.name -PassThru}

Of course you might still need to use select to get your output restricted to the properties you need but it is another option.

1 Comment

I think your Post Question-Edit answers my question: I can't do something like select author, title, publisher.name and I have to do something a bit more complicated to get the publisher name. I'm learning what does and doesn't work with PowerShell and that's really what I wanted to find out. Cheers.
1

I too was on the hunt for how to accomplish a select of an object's sub-property. In my case it was in order to export a DNS Server's Zone data. I'll share the guts on what I used to accomplish my goal and this posting here helped!

To do what you were looking for specifically try modifying your code as follows:

$xmlDoc.catalog.book | Select Author, Title, -Expand Publisher | Select Author, Title, Name | Sort Author | FT -auto

Based on the table output you provided the above should work. It worked for me which you'll see below.

This script worked great for what I needed and is a blend of different ideas. Hopefully it works for someone else.

$Zones = @(Get-DnsServerZone)
ForEach ($Zone in $Zones) {
    Write-Host "`n$($Zone.ZoneName)" -ForegroundColor "Yellow"
    $Data = New-Object System.Object
    $Data = $Zone | Get-DnsServerResourceRecord
    $Data | Add-Member -MemberType NoteProperty -Name "ZoneName" -Value $Zone.ZoneName
    $Data += $Data
    $Data | Select-Object ZoneName, HostName, RecordType -Expand RecordData | Select ZoneName, HostName, RecordType, IPv4Address, HostNameAlias, NameServer, PrimaryServer, ExpireLimit, MinimumTimeToLive, RefreshInterval, ResponsiblePerson, RetryDelay, SerialNumber, DomainName, Port, Priority, Weight | Sort RecordType, HostName | Export-Csv -NoTypeInformation "$($Zone.ZoneName).csv"
}

The Yellow Foreground is handy when you're looking at the output prior to export. Just put the } right after HostName and before | Export-Csv like this: ... Sort RecordType, HostName }

1 Comment

Tried it but got the following error: Select-Object : A positional parameter cannot be found that accepts argument 'publisher'. I wonder if it's because the book object is of type System.Xml.XmlElement?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.