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.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
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.
Function ConvertTo-HashTable { [cmdletbinding()] Param( [Parameter(Position=0,Mandatory=$True,HelpMessage="Please specify an object", ValueFromPipeline=$True)] [object]$InputObject, [switch]$NoEmpty ) Process { Write-Verbose "Converting an object of type $($_.GetType().Name)" #get propery names $names=$InputObject | get-member -MemberType properties | select-object -expandproperty name #define an empty hash table $hash=@{} #go through the list of names and add each property and value to the hash table $names | foreach-object { Write-Verbose "Adding property $_" $hash.Add($_,$inputobject.$_) } #foreach if ($noEmpty) { Write-Verbose "Parsing out empty values" #define a new hash $defined=@{} #get items from $hash that have values and add to $defined $hash.keys | foreach-object { if ($hash.item($_)) { $defined.add($_,$hash.item($_)) } } Write-Verbose "Writing the result to the pipeline" Write-Output $defined } else { Write-Verbose "Writing the result to the pipeline" Write-Output $hash } #If $noempty }#close process }#end function
As an object is processed by the function it uses Get-Member to retrieve all of the object's properties.
$names=$InputObject | get-member -MemberType properties | select-object -expandproperty name
The function then walks the object and adds each property name and value to a hash table.
#go through the list of names and add each property and value to the hash table $names | foreach-object { Write-Verbose "Adding property $_" $hash.Add($_,$inputobject.$_) } #foreach
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.
if ($noEmpty) { Write-Verbose "Parsing out empty values" #define a new hash $defined=@{} #get items from $hash that have values and add to $defined $hash.keys | foreach-object { if ($hash.item($_)) { $defined.add($_,$hash.item($_)) } } Write-Verbose "Writing the result to the pipeline" Write-Output $defined
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:
PS S:\> $h=get-service spooler | convertto-hashtable PS S:\> $h Name Value ---- ----- ServiceName spooler CanPauseAndContinue False DisplayName Print Spooler CanShutdown False Site Name spooler MachineName . ServiceType Win32OwnProcess, InteractiveProcess Status Running ServiceHandle SafeServiceHandle Container DependentServices {} RequiredServices {HTTP, RPCSS} ServicesDependedOn {HTTP, RPCSS} CanStop True
Or to filter out the empty values:
PS S:\> get-service spooler | convertto-hashtable -NoEmpty Name Value ---- ----- ServiceName spooler DisplayName Print Spooler RequiredServices {HTTP, RPCSS} Name spooler MachineName . Status Running ServiceHandle SafeServiceHandle ServiceType Win32OwnProcess, InteractiveProcess ServicesDependedOn {HTTP, RPCSS} CanStop True
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.
That is a good generalization of what I did here to unwind the wrapped properties of an adsi search result object.
http://gallery.technet.microsoft.com/scriptcenter/Extract-arbitrary-list-of-6f59d3b4
“I’d love to write the hash table to the pipeline with sorted keys, but that may have to wait.”
Process {
Write-Verbose "Converting an object of type $($_.GetType().Name)"
#get propery names
$names=$InputObject | get-member -MemberType properties | select-object -expandproperty name
#define an empty hash table
$hash= new-object system.collections.specialized.ordereddictionary
#go through the list of names and add each property and value to the hash table
$names | sort | foreach-object {
Write-Verbose "Adding property $_"
$hash.Add($_,$inputobject.$_)
} #foreach
if ($noEmpty) {
Write-Verbose "Parsing out empty values"
#define a new hash
$defined=new-object system.collections.specialized.ordereddictionary
#get items from $hash that have values and add to $defined
$hash.keys | foreach-object {
if ($hash.item($_)) {
$defined.add($_,$hash.item($_))
}
}
Write-Verbose "Writing the result to the pipeline"
Write-Output $defined
}
else {
Write-Verbose "Writing the result to the pipeline"
Write-Output $hash
} #If $noempty
}#close process
}#end function
I knew it could be done. Unfortunately it takes more knowledge than a typical IT Pro is likely to have. Thanks for your work.