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.