Using .net nested objects in powershell thinking aloud gas x breastfeeding side effects

Have you ever run across a PowerShell cmdlet that produces really nice default console output in table format that you would like to save as a .csv file? You might think it’s as simple as piping the output to Export-Csv. And sometimes it is. But the cmdlet author determines what is output to the console. If that default output contains properties from nested objects returned by the cmdlet, you will have to access those nested objects to create a useful export to .csv.

That means you need to be comfortable with PowerShell objects. Since objects can themselves contain collections of objects, it’s important to understand how to inspect object properties from the PowerShell console. While an .Net app developer might be quite comfortable with objects-within-objects, DevOps folks, administrators and cloud architects — the target audience for PowerShell — might not be.

Before answering that question, allow me to introduce the most useful cmdlet in PowerShell: Get-Member. The doc simply says that this cmdlet “Gets the properties and methods of objects.” That’s quite an understatement. In my PowerShell work, I use gm (the alias for Get-Member) more than any other cmdlet, bar none. That’s because it’s a quick and handy way of discovering what objects are contained within higher level objects. Let’s use Get-Member with Get-AzureRmVm.

Piping the output of Get-AzureRmVm to Get-Member retrieves a collection of one of more objects of type Microsoft.Azure.Commands.Compute.Models.PSVirtualMachineList. This object contains properties that are themselves objects of varying types. Note in this screenshot that the properties HardwareProfile and StorageProfile are nested objects contained in the PSVirtualMachineList object. Using PowerShell Get-Member to find the properties of a object (click to enlarge)

Now we can see why a simple piping of Get-AzureRmVm output to Export-Csv produces object type output for variables instead of the properties of those objects. It’s because we need to be specific about which properties of nested objects we want Export-Csv to use.

To work down the list of objects, we can simply pipe the nested object to Get-Member exactly the same way to see what its properties and methods are. I call this “PowerShell object sleuthing” and, while you can find the definitions of objects’ properties online, it’s just simpler and faster to use Get-Member. Here’s an example of discovering the properties of the StorageProfile object returned by Get-AzureRmVm. Notice that the object Microsoft.Azure.Management.Compute.Models.StorageProfile contains yet another object of type Microsoft.Azure.Management.Compute.Models.OSDisk. It’s this last object that contains a property ( OsType) that we liked in the default console output and which we want to store in a .csv. Finding the operating system of an Azure VM (click to enlarge)

Here’s an example PowerShell script that mimics the console output of Get-AzureRmVm. In this script, all VMs in a subscription are passed to the pipline where we retrieve and format properties we are interested in, add them to an [ordered] hash table and use that table as the properties of a custom PowerShell object which represents a row of output in our .csv. An array containing our custom objects is piped to Export-Csv, producing precisely the output we want.