Reputation: 19688
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
Upvotes: 26
Views: 23962
Reputation: 1145
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.
Upvotes: 57
Reputation: 11
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 }
Upvotes: 1
Reputation: 46710
It would be easier if you had something actual repeatable for us to test but we can fake that with Get-Item
s 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.
Upvotes: 9