How to Supercharge PowerShell Objects for Hyper-V

Save to My DOJO

How to Supercharge PowerShell Objects for Hyper-V

The best thing about working with PowerShell is that everything is an object. This makes it easy to work with the properties of the thing you need to manage without a lot of scripting or complex text parsing. For example, when using the Hyper-V PowerShell module it is trivial to get specific details of a virtual machine.

Getting virtual machine properties with PowerShell

There are many properties to this object. You can pipe the object to Get-Member to see the definition or Select-Object to show all properties and their values.

Get-VM Win10 | Get-Member
Get-VM Win10 | Select-object -Property *

But what you want more? I usually do. For example, there is a CreationTime property for the virtual machine object. I’d like to be able to report on how old the virtual machine is. For a one-and-done approach I could write a command like this:

Get-VM | Select-Object -Property Name,CreationTime,
@{Name="Age";Expression={(Get-Date) - $_.creationtime}} |
Sort-Object -Property Age -Descending

Defining a new custom property

Or maybe I’d like the MemoryAssigned value to be formatted in MB.

Get-VM | Select-Object -Property Name,State,
@{Name="MemoryAssignedMB";Expression = {$_.memoryassigned/1mb}}

Defining a custom property for assigned memory

The syntax is to define a hashtable with 2 keys: Name and Expression. The Name value is what you want to use for your custom property name and the Expression is a PowerShell scriptblock. In the scriptblock you can run as much code as you need. Use $_ to reference the current object in the pipeline. In the last example, PowerShell looks at the MemoryAssigned value for the CentOS virtual machine object and divides it by 1MB. Then it moves on the DOM1 and divides the value (2147483648) by 1MB to arrive at 2048 and so on.

Using Select-Object this way is great for your custom scripts and functions. But suppose I want to get these values all the time when working with the object in the console interactively. I don’t want to have to type all that Select-Object code every single time. Fortunately, there is another approach.

PowerShell’s Extensible Type System

PowerShell has an extensible type system. This means you can extend or modify the type definition of an object. PowerShell takes advantage of this feature all the time. Many of the properties you’ve seen in common objects have been added by Microsoft. You can use the Get-TypeData cmdlet to view what additions have been made to a given type.

$td = Get-TypeData microsoft.hyperv.powershell.virtualmachine
$td.Members

default extensions to the virtual machine object

You can see these additions with Get-Member.

Viewing the type additions

By now, you are thinking, “How can I do this?”. The good news is that it isn’t too difficult. Back in the PowerShell stone age you would have had to create a custom XML file, which you can still do. But I think it is just as easy to use the Update-TypeData cmdlet. I’ll give you some examples, but please take the time to read the full help and examples. One thing to keep in mind is that any type extensions you make last only as long as your PowerShell session is running. The next time you start PowerShell you will have to re-define them. I dot source a script file in my profile script that adds my type customizations.

Updating Type Data

The first thing you will need to know is the object’s type name. You can see that when piping to Get-Member.

$t = "Microsoft.Hyperv.Powershell.VirtualMachine"

When you define a new type you need to determine the membertype. This will be something like a ScriptProperty or Alias. A ScriptProperty is a value that is calculated by running some piece of PowerShell code. If you’ve created a custom type with Select-Object to test, as I did earlier, you will re-use that expression scriptblock. And of course, you need to define a name for your new property.

Update-TypeData -TypeName $t -MemberType ScriptProperty -MemberName Age -Value {(Get-Date) - $this.CreationTime} -force

With this code, I’m defining a new script property called Age. The value will be the result of the scriptblock that subtracts the CreationTime property of the object from now. The one difference to note compared to my Select-Object version is that here use $this instead of $_.

Update-TypeData -TypeName $t -MemberType ScriptProperty -MemberName MemoryAssignedMB -Value {$this.memoryassigned/1mb} -force
Update-TypeData -TypeName $t -MemberType AliasProperty -MemberName Created -Value CreationTime -force

I went ahead and also created an alias property of “Created” that points to “CreationTime”. If you try to create a type extension that already exists PowerShell will complain. I typically use -Force to overwrite any existing definitions. But now I can see these new type members.

Verifying new VM type extensions

And of course, I can use them in PowerShell.

Using the new type extensions in PowerShell

There’s really no limit to what you can do. Here is a script property that tells me when the VM started.

Update-Typedata -TypeName $t -MemberType ScriptProperty -MemberName LastStart -Value {
 if ($this.uptime -gt 0) {
   (Get-Date).AddSeconds(- ($this.uptime.totalseconds))
 }
 else {
   $Null 
 }
} -force

and here is some code that takes the memory properties and creates an ‘MB’ version of each one. I’m using some PowerShell scripting and splatting to simplify the process.

$orig = 'MemoryMaximum','MemoryMinimum','MemoryStartup','MemoryDemand'  
$params = @{
 TypeName   = $t 
 MemberType = "ScriptProperty"
 MemberName = ""
 Value      = ""
 Force      = $True
}

foreach ($item in $orig) {
  $params.MemberName = "$($item)MB"
  #get-vm win10 | select name,$item
  $sb = [scriptblock]::Create("`$this.$item /1mb")
  $params.Value = $sb
  Update-TypeData @params
}

Now I have all sorts of information at my fingertips.

Taking advantage of all the new properties

As long as I run the Update-Typedata commands I will have this information available. In my PSHyperVTools module, which you can install from the PowerShell Gallery, it will add some of these type extensions automatically, plus a few more. You can read about it in the project’s GitHub repository.

Does this look like something you would use? What sort of type extensions did you come up with? What else do you wish you could see or do? Comments and feedback are always welcome.

Altaro Hyper-V Backup
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

Leave a comment or ask a question

Your email address will not be published. Required fields are marked *

Your email address will not be published.

Notify me of follow-up replies via email

Yes, I would like to receive new blog posts by email

What is the color of grass?

Please note: If you’re not already a member on the Dojo Forums you will create a new account and receive an activation email.