ps1.soapyfrog.com

doing inappropriate things with powershell

Pages

  • About
  • Downloads
  • Archives

Search

Popular Posts

  • Grrr 1.1 and Big Invaders
  • Space Invaders
  • Convert images to text (ASCII art)
  • Cmdlet clashes
  • Console screen grabs in html

Recent Posts

  • Grrr source code, including Invaders
  • Google going down the pan
  • Cmdlet clashes
  • Grrr 1.1 and Big Invaders
  • Grrr, Cmdlets and PSInvaders revival

Categories

  • Announce (7)
  • Cmdlets (2)
  • Cool (16)
  • Grrr (6)
  • Hint (2)
  • Invaders (5)
  • Odd (2)
  • PowerShell (27)
  • Quiz (3)
  • Rant (7)
  • Uncategorized (1)
  • Utility (5)

Months

  • August 2007 (1)
  • April 2007 (1)
  • March 2007 (1)
  • February 2007 (3)
  • January 2007 (25)
  • December 2006 (1)

Bookmarks

  • Blogroll
    • $script Fanatics
    • blog.soapyfrog.com
    • Brian Long
    • Lee Holmes
    • Nik Crabtree
    • PowerShell-Scripting (French)
    • Richy Rich
    • The PowerShell Guy
    • Windows PowerShell
  • Links
    • Carbon-neutral web hosting!

Meta

  • Log in
  • Posts RSS
  • Comments RSS
  • Valid XHTML
  • Valid CSS
« Getting normality back
Pipe or no pipe? »
 

Hashes and properties

15 Jan 2007 04:39 pm// PowerShell, Quiz    

I really like the way that PowerShell handily formats pipeline objects when displaying them in the console, eg get-childitem in a file system directory returns a collection of file objects and the output is like the old DOS dir command.

Additionally, I really like the way that hashes behave like objects with named properties. For example:

$a=@{"name"="bob";"age"=42}
$a.name # outputs "bob"
$a.age # outputs 42

Unfortunately, if you have a list/array of hashes with the same keys, you cannot benefit from this built-in formatting. The output comes out in two columns, keyed Name and Value.

I want a way to have the properties of the hash be the keys and the values be the values associated with those keys.

Consider the array of hashes created by this code:

$rnd = new-object Random
$list = @()
1..5 | % {
  $o = @{}
  "keyone","keytwo" | % {
    $o["$_"] = "x$($rnd.next(100))"
  }
  $list += $o
}

This creates an array of five hashes, each with two keys (keyone and keytwo) with random values.

If we type $list in the console, we get something like this:

Name                           Value
----                           -----
keyone                         x11
keytwo                         x33
keyone                         x47
keytwo                         x47
keyone                         x72
keytwo                         x57
keyone                         x85
keytwo                         x9
keyone                         x43
keytwo                         x35

This is not what I want. I want the columns to be keyone and keytwo with the values below.

One way around this is to do something like this (all on one line):

$list | select-object @{Name="keyone";Expression={$_.keyone}},@{Name="keytwo";Expression={$_.keytwo}}

Behold! we get what I want:

keyone                                                      keytwo
------                                                      ------
x72                                                         x71
x18                                                         x6
x59                                                         x60
x37                                                         x39
x63                                                         x10

Unfortunately, this requires me to know which columns I want in advance, and with more than two columns, it gets rather verbose.

A solution, that works well for me, is to write a function that replaces hashes in the pipe with a custom PowerShell object with added properties… the cmdlet add-member comes the rescue:

function convertto-hashobject {
  process {
    if ($_ -is [Collections.IDictionary]) {
      $hash = $_
      $out = new-object object
      foreach ($k in $hash.Keys) {
        $out = add-member -i $out -type "noteproperty" -name "$k" -force -passthru $hash[$k]
      }
      $out
    }
    else {
      $_
    }
  }
}

Now, regardless of the hash contents, we can do this:

$list | convertto-hashobject 

to get this:

keyone                                                      keytwo
------                                                      ------
x72                                                         x71
x18                                                         x6
x59                                                         x60
x37                                                         x39
x63                                                         x10

Now, this post is tagged as a Quiz, because I’m sure there is a better way of doing this. Perhaps something blindingly obvious that I missed, or something really cunning.

Let me know!

One comment to “Hashes and properties”

  1. On 31 Jan 2007 at 4:09 am, Andrew Savinykh said:   

    Well, I kind of asked the same question back in august on the microsoft powershell newsgroup. Here is a cached copy, since the original post seemed to be expired: http://www.vista64.net/forums/showthread.php?t=12840

    I got no reply, but later in another thread I got this:
    http://www.vista64.net/forums/showthread.php?t=13083

    So basically, there is no better way of doing this as of august last year.

Copyright © 2006-2008 Adrian Milliner

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 2.5 License.