Summary: Microsoft Scripting Guy, Ed Wilson, shows you how to create a custom Hyper-V Resource Metering reset report by using Windows PowerShell 3.0.

Microsoft Scripting Guy, Ed Wilson, is here. Well, I found a pretty cool Pandora app for my Windows RT Surface, and so I am listening to a cool Rolling Stones song as I type this. Actually I am surprised at the quality of the music my little Surface RT is spewing out.

United States FTC disclaimer: The Microsoft Scripting Guys work for the Microsoft Corporation. I have been provided with a Windows Surface RT. In addition, the Microsoft Corporation provides me a salary, health insurance, bonus, U.S. national holidays off, and annual leave. The Microsoft Corporation, however, has not purchased for me the Bluetooth wedge mouse or type cover that I use with my Surface. In addition, the Microsoft Corporation did not buy the Windows Surface RT that the Scripting Wife uses.

Anyway, I am playing around this morning, happy that so far I have no meetings either today or tomorrow. In fact, the week is shaping up tremendously … and the Scripting Wife and I are planning on heading out on Friday night to see our friends perform at a local club tomorrow evening. We generally do not hang out with people who do not do Windows PowerShell, so this will be sort of a different experience.

Working with the virtual machine metering report

The VMMeteringReportForVirtualMachine object does not display the amount of time that has lapsed since the Resource Metering was last reset.

Note   See my Use PowerShell to Reset Hyper-V Resource Metering Blog post from Tuesday for more information about resetting the Resource Metering report.

It dawned on me that the MeteringDuration property contains a TimeSpan object. I confirmed this by piping to Get-Member as shown here.

14:16 C:\> get-vm * | Measure-VM | gm -Name MeteringDuration

TypeName: Microsoft.HyperV.PowerShell.VMMeteringReportForVirtualMachine

Name             MemberType Definition

----             ---------- ----------

MeteringDuration Property   System.Nullable[timespan] MeteringDuration {get;}

So, I decided to pipe the Get-VM command to the Measure-VM cmdlet and then create a custom object. I named one property TimeSpan, and I cast the MeteringDuration property to a [timespan] object. The code is shown here.

Get-VM -vmname * | Measure-VM |

    select-Object vmname,

     @{LABEL="Timespan";EXPRESSION={[timespan]$_.MeteringDuration}}

When I run the code, the following output is shown.

VMName                                            Timespan                                       

------                                            --------                                       

sql1                                              02:49:51.1750000                               

DC1                                               02:49:51.1760000                                

C2                                                02:49:51.1530000                               

c1                                                02:49:51.1140000                               

 

The big problem with this output is that I have no idea if the TimeSpan represents 2 days or 2 hours. Well, I guess the 49 would probably be minutes or seconds, and the 1750000 is probably something like ticks, but it would be nice to see the TimeSpan expanded.

Creating a new object with TimeSpan details

So, I decide I want to create a new object that expands the Days, Hours, and Minutes properties from the TimeSpan object. Because I now have a custom object that contains the VMName and a TimeSpan object, it is pretty easy for me to create the desired object. I cannot pipe directly to the New-Object cmdlet, but I can pipe to the Foreach-Object cmdlet.

So, I throw the Foreach-Object cmdlet into the mixture, and in the associated ScriptBlock, I add my New-Object cmdlet. I can specify properties by using a HashTable notation. So first off, I create a property named name, and I assign the value from the VMName property of my previous object. Now I use the TimeSpan property from my previous object, and I directly access the Days, Hours, and Minutes. The last step is to choose the type of object—for this, the psobject type is fine. Here is the code I created.

Get-VM -vmname * | Measure-VM |

    select-Object vmname,

     @{LABEL="Timespan";EXPRESSION={[timespan]$_.MeteringDuration}} |

    Foreach-Object {

       New-Object -Property @{

        Name=$_.vmname;

        Days=$_.TimeSpan.Days;

        Hours=$_.TimeSpan.hours

        Minutes=$_.timespan.minutes} -type psobject

       }

When I run the above code, the output shown here displays in the output pane on my Windows PowerShell ISE.

                    Hours                     Days                  Minutes Name                  

                   -----                     ----                  ------- ----                  

                       3                        0                       51 sql1                  

                       3                        0                       51 DC1                   

                       3                        0                       51 C2                    

                       3                        0                       51 c1                    

Hmm, the output is what I want, but the order is all messed up. Oh well, I guess I will need to use Format-Table to fix up the formatting.

Formatting the output

The problem with the previous output is that I wanted the Name of the virtual machine, and then I wanted the Days, Hours, and Minutes to display. I could have just put those properties in order and use the Format-Table, but because I am playing around, I decided to do something better.

One of the seldom used parameters for the Format-Table cmdlet is the GroupBy parameter. Well, did you know I could supply a ScriptBlock for the GroupBy parameter? If you did know that, have you forgotten it? Well, I decided to add a ScriptBlock for the GroupBy parameter. So, I group by Computer Name, but I change the Label to “Time Since Last VM Report” and then I pick up the name of the virtual machine. Here is the code—it is cool!

        Format-table -property days, hours, minutes -AutoSize -GroupBy @{

        Label="Time since last VM Report";

        Expression={$_.name} }

 The output is shown in the image that follows.

Image of command output

The complete Get-VMResourceReportConvertToObjectFormatTable.ps1 is shown here.

get-vm -vmname * | Measure-VM |

    select-Object vmname,

     @{LABEL="Timespan";EXPRESSION={[timespan]$_.MeteringDuration}} |

    Foreach-Object {

       New-Object -Property @{

        Name=$_.vmname;

        Days=$_.TimeSpan.Days;

        Hours=$_.TimeSpan.hours

        Minutes=$_.timespan.minutes} -type psobject

       } |

       Format-table -property days, hours, minutes -AutoSize -GroupBy @{

        Label="Time since last VM Report";

        Expression={$_.name} }

I uploaded the complete script to the Scripting Guys Script Repository. This should make it easy for you to download and play with the code. Hope you have an awesome day.

Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy