PowerShell Hyper-V Memory Report

Since moving to Windows 8, I’ve continued exploring all the possibilities around Hyper-V on the client, especially using PowerShell. Because I’m trying to run as many virtual machines on my laptop as I can, memory considerations are paramount as I only have 8GB to work with. Actually less since I still have to run Windows 8!

Anyway, I need to be able to see how much memory my virtual machines are using. The Get-VM cmdlet can show me some of the data.

Actually, there are more properties I can get as well.

Those values are in bytes so I would need to reformat them to get them into something more meaningful like bytes. Not especially difficult, but not something I want to have to type all the time. Now, I can also get memory information with Get-VMMemory and this is formatted a little nicer.

What I like about this cmdlet is that it also shows the buffer and priority settings.

In the end, I decided the best course of action was to build my own function that combined information from both cmdlets. The result is a custom object that gives me a good picture of memory configuration and current use. The function, Get-VMMemoryReport, is part of a larger HyperV toolkit module I’m developing but I thought I’d share this with you now.

I wrote the function with the assumption of piping Hyper-V virtual machines to it. Although I can also pipe names to it and the function will then get the virtual machine.

Once the function has the virtual machine object, it also gets data from Get-VMMemory.

Finally, it creates a hash table using the new [ordered] attribute so that the key names will be displayed in the order I enter them. I use this hash table to write a custom object to the pipeline. I could have used the new [pscustomobject] attribute as well, but I felt in a script using New-Object was a bit more meaningful. With this command, I get output like this:

Or I can explore the data in other ways. I can create an HTML report, export to a CSV or take advantage of Out-GridView.

Here’s the report for my currently running virtual machines.

The function defaults to connecting to the localhost, but I am assuming that if you have an Hyper-V server you could use this from any system that has they Hyper-V module also installed. I don’t have a dedicated Hyper-V server to test with so maybe someone will confirm this for me.

In the meantime, download Get-VMMemoryReport and let me know what you think.

Export and Import Hash Tables

I use hash tables quite a bit and with the impending arrival of PowerShell 3.0 I expect even more so. PowerShell v3 allows you to define a hash table of default parameter values. I’m not going to to cover that feature specifically, but it made me realize I needed a better way to export a hash table, say to a CSV file. So I put together a few functions to do just that.

To walk you through them, here’s a simple hash table.


$hash=@{Name="jeff";pi=3.14;date=Get-Date;size=3 }
$hash
Name Value
---- -----
Name jeff
pi 3.14
date 2/2/2012 10:04:54 AM
size 3

I want to export this to a CSV file, but because PowerShell is all about the objects, I want to be sure to get the type information as well. Otherwise when I go to importing, everything will be a string. Here’s what I can expect to export:


$hash.GetEnumerator() | Select Key,Value,@{Name="Type";Expression={$_.value.gettype().name}}

Key Value Type
--- ----- ----
Name jeff String
pi 3.14 Double
date 2/2/2012 10:05:57 AM DateTime
size 3 Int32

That looks good. I can take this command and run it through Export-CSV which gives me this file:

#TYPE Selected.System.Collections.DictionaryEntry
"Key","Value","Type"
"Name","jeff","String"
"pi","3.14","Double"
"date","2/2/2012 10:05:57 AM","DateTime"
"size","3","Int32"

Perfect. Later, I will need to import this file and recreate my hash table. I can use Import-CSV as a starting point.


PS C:\> import-csv hash.csv

Key Value Type
--- ----- ----
Name jeff String
pi 3.14 Double
date 2/2/2012 10:05:57 AM DateTime
size 3 Int32

Good so far. All I need to do is create a hash table and add each entry to it. I could do something like this:


Import-csv hash.csv | foreach -begin {$hash=@{}} -process {$hash.Add($_.Key,$_.Value)} -end {$hash}

But if I do this, everything will be a string. Since I have Type information, let’s use it.


Import-Csv -Path $path | ForEach-Object -begin {
#define an empty hash table
$hash=@{}
} -process {
<# if there is a type column, then add the entry as that type otherwise we'll treat it as a string #>
if ($_.Type) {

$type=[type]"$($_.type)"
}
else {
$type=[type]"string"
}
Write-Verbose "Adding $($_.key)"
Write-Verbose "Setting type to $type"

$hash.Add($_.Key,($($_.Value) -as $type))

} -end {
#write hash to the pipeline
Write-Output $hash
}

Here I’m taking the Type value from the import and turning it into a System.Type object which I can then use to cast each value to the correct type. I’m checking for the Type property because I might have a CSV file without it. But as long as I have column headings for Key and Value this will work.

I turned all of this into a pair of advanced functions, Export-HashtoCSV and Import-CSVtoHash.


PS C:\> $hash | Export-HashtoCSV myhash.csv
PS C:\> $newhash=Import-CSVtoHash .\myhash.csv -verbose
VERBOSE: Importing data from .\myhash.csv
VERBOSE: Adding Name
VERBOSE: Setting type to string
VERBOSE: Adding pi
VERBOSE: Setting type to double
VERBOSE: Adding date
VERBOSE: Setting type to System.DateTime
VERBOSE: Adding size
VERBOSE: Setting type to int
VERBOSE: Import complete
PS C:\> $newhash

Name Value
---- -----
Name jeff
pi 3.14
date 2/2/2012 10:05:57 AM
size 3
PS C:\> $newhash.date

Thursday, February 02, 2012 10:05:57 AM
PS C:\> $newhash.pi.gettype().name
Double

This certainly fulfills my needs. You can download a script file with both functions, including help. As always, enjoy and I hope you’ll let me know how these work out for you.

Convert Text to Object

Today I have another tool in my new battle regarding turning command line tools into PowerShell tools. The bottom line is we want to have objects written to the pipeline. At the PowerShell Deep Dive in Frankfurt there was a suggestion about providing tools to help with the transformation from CLI to PowerShell and this is one of the items I came up with.

Many command line tools write output in a structured format. For example run this command:

There’s an “object” staring at us for each task. As an aside, don’t focus on the command line tool I’m using, pay attention to the technique. To turn output like this into ah object we simply need to split each line at the colon. The first index of the array will be the “property” name and the second index is the value. Here’s the function I pulled together.

The function processes each incoming line of text and splits it on the delimiter. The default is the colon since many CLI tools seem to use it.

Since I prefer property names without spaces I remove them from index 0 of the array. I’ve also found it helpful to trim everything to eliminate extra white space.

Each line is then added to a hash table.

When the hash table is complete it is used to create a new object.

The other “trick” I added is to group lines into an object. This let’s me take say every 5 lines of text and make that a single object. I create a counter and increment it whenever a line is processed. When the counter meets the limit, the object is created, the hash table is cleared and the process repeats.

Now I can run a command like this:

The output looks similar but now I have objects so I can take advantage of PowerShell. Here are some examples:

This is by no means perfect but I’d like to think it is a good start. For example, one downside is that all properties are strings where it would be nicer to have properties of an appropriate type. Still, I hope you’ll try this out and let me know what you think.

Download Convert-TexttoObject

Update
A newer version of the script can be found at http://jdhitsolutions.com/blog/2012/01/convert-text-to-object-updated/

Friday Fun Convert Object to Hash Table

I’ve been working on a few PowerShell projects recently and one requirement I had was to turn an object into a hash table. I thought this was something that was already handled in PowerShell but I couldn’t find a cmdlet or an easy .NET technique. So I wrote my own function, ConvertTo-Hashtable.

The function is designed to accept pipelined input and turns each object into an associative array, i.e., a hash table, and write the hash table to the pipeline.

As an object is processed by the function it uses Get-Member to retrieve all of the object’s properties.

The function then walks the object and adds each property name and value to a hash table.

This hash table object, $hash, eventually is written to the pipeline. This process happens to each piped in object. However, I also added a function parameter, -NoEmpty, to filter out properties with no values. When specified, the function creates a second hash table and then checks each key in $hash. If the corresponding item has a value, the key and value are added to the secondary hash.

The secondary hash is then written to the pipeline. I had to take this approach because PowerShell doesn’t like it when you try to modify and enumerate a hash table at the same time. Here’s how you might use it:

Or to filter out the empty values:

Granted, your use case for something like this is probably pretty limited. But there are some good technique examples here on working with hash tables.

The one nagging problem, at least until PowerShell v3, is that it is very difficult to write a sorted hash table. I’d love to write the hash table to the pipeline with sorted keys, but that may have to wait.

In the meantime, feel free to download and experiment with ConvertTo-Hashtable.

Friday Fun What a CHAR!

Last week I posted a PowerShell snippet on Twitter. My original post piped an array of integers as [CHAR] type using an OFS. Don’t worry about that. As many people reminded me, it is much easier to use the -Join operator.

I’ll let you try that on your own. The [CHAR] type is used to represent a character as an integer value, like this:

For this week’s Friday Fun I thought it would be nice to translate a string of text into corresponding character values. It looks like a secret code! Or we could use the translation in a join scriptblock. So I put together a little script I call Translate-ToChar.ps1. The script takes a string of text and writes an array of [CHAR] objects.

The script begins by defining a map hash table for what I think are all characters you are likely to find on a US keyboard. These should be character values 33 through 125 which I get using the range (..) operator.

Each number is piped to ForEach object where I add it to the hash table. In order to get the hash table key to work properly I cast the number as a string and the hash table value is the same number cast as a [CHAR]. Now we can begin breaking the string apart and “translating” it.

The script splits the string into a character array using the default delimiter of a space. Because I’m going to be using a pipelined expression, I save the current letter as a variable. It will keep things straight in a moment.

The next step is to find the character in the hash table values. I found the best way to accomplish this was to call the hash table’s GetEnumerator() method. This way I can pipe it to Where-Object and find the corresponding key.

Notice I’m using the case sensitive -ceq operator. The Name property of the hash table enumerator is the key value, or in other words the corresponding [CHAR] integer. With me still? This value is added to an array for the final result. In fact the default isĀ to simply write $values to the pipeline. But, I’ve included a -Scriptblock parameter to have the script write a scriptblock to the pipeline using the -Join operator I mentioned earlier. Now for the interesting part.

I have an array variable which needs to be expanded into the scriptblock. This won’t work:

I’ll end up with a scriptblock but have no way of resolving $values once the script ends. So instead I create a string with $values knowing that PowerShell will expand it. And because I want the array to be expanded as a comma separated string, I’ll specify the $ofs variable as a comma. The default is a space.

The variable $t is now a string with all of the integer values from $values as a comma separated list. I can turn this into scriptblock like this:

The scriptblock gets written to the pipeline. So, I could run the script like this:

Now I can use $a however I want. Or I could create a scriptblock.

I can invoke $b anytime I want to see the message.

While I don’t expect you to be running this in production I hope you picked up some tips on using hash tables, arrays, scriptblocks and casting variable types.

Download Translate-ToChar