The reason we're building a custom object here is because we want to merge data from multiple sources into a single object. The Get-Mailbox cmdlet does not return the Title or Department properties that are tied to a user account: the Get-User cmdlet needs to be used to retrieve that information. Since we may want to generate a report that includes information from both the Get-Mailbox and Get-User cmdlets for each individual user, it makes sense to build a custom object that contains all of the required information. We can then pipe these objects to other cmdlets that can be used to export this information to a file.
We can modify one of our previous code samples and pipe the output to a CSV file used to document this information for the current user population:
$mailboxes |
Select-Object Name,
Database,
@{n="Title";e={(Get-User $_.Name).Title}},
@{n="Dept";e={(Get-User $_.Name).Department}} |
Export-CSV -Path C:\Scripts\report.csv -NoTypeInformation
Keep in mind that even though you can also create calculated properties using the Format-Table cmdlet, you'll want to use Select-Object, as shown previously, when converting these objects to CSV or HTML reports. These conversion cmdlets do not understand the formatting information returned by the Format-Table cmdlet, and you'll end up with a lot of useless data if you try to do this.
When building custom objects with the Select-Object cmdlet, we can select existing properties from objects coming across the pipeline and also add one or more calculated properties. This is done using a hash table that defines a custom property name in the hash table key and a script block within the hash table value. The script block is an expression where you can run one or more commands to define the custom property value. In our previous example, you can see that we've called the Get-User cmdlet to retrieve both the Title and Department properties for a user that will be assigned to calculated properties on a new object.
The syntax for creating a calculated property looks a little strange at first glance since it uses name and expression keywords to create a hash table that defines the calculated property. You can abbreviate these keywords as shown next:
$mailboxes |
Select-Object Name,
Database,
@{n="Title";e={(Get-User $_.Name).Title}},
@{n="Dept";e={(Get-User $_.Name).Department}}
The property name uses the string value assigned to n, and the property value is assigned to e using a script block. Abbreviating these keywords with n and e just makes it easier to type. You can also use label or l to provide the calculated property name.
Using the New-Object cmdlet and assigning a hash table to the -Property parameter is a quick and easy way to create a custom object. The only issue with this technique is that the properties can be returned in a random order. This is due to how the .NET Framework assigns random numeric values to hash table keys behind the scenes, and the properties are sorted based on those values, not in the order that you've defined them. The only way to get the properties back in the order you want is to continue to pipe the command to Select-Object and select the property names in order, or use one of the other techniques shown in this recipe.
Creating an empty custom object and manually adding note properties with the Add-Member cmdlet can require a lot of extra typing, so generally this syntax is not widely used. This technique becomes useful when you want to add script methods or script properties to a custom object, but this is an advanced technique that we won't need to utilize for the recipes in the remainder of this book.