Automatically Create a PowerShell Hash Table

Automatically Create a PowerShell Hash Table

  • Comments 2
  • Likes

Summary: Learn how to automatically create a Windows PowerShell hash table and extra process data.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I thought your article introducing hash tables was pretty interesting. I was wondering how I might populate a hash table. Can you explain how to do this easily?

—AC

 

Hey, Scripting Guy! Answer Hello AC,

Microsoft Scripting Guy Ed Wilson here. This is a pretty cool time of the year down here in Charlotte, North Carolina. Well, not literally cool, but figuratively anyway. The thing that is so nice is that fresh peaches are showing up everywhere. This is because locally grown peaches from South Carolina and from Georgia are easily obtained.

AC, if I need to populate a hash table with two or three key/value pairs, I generally do it manually and separate each key/value pair with a semicolon. One thing to note is that while the value portion requires quotation marks, the key portion does not. In the last key/value pair, I illustrate this. The code to create three key/value pairs, assign them to a hash table stored in the variable $hash, and then display the contents of that variable is shown here:

PS C:\Users\ed.WOODGROVE> $hash = @{"key1"="value1";"key2"="value2";key3="value3"}

PS C:\Users\ed.WOODGROVE> $hash 

Name               Value

----                   -----

key3                  value3

key2                  value2

key1                  value1

 

If I want to retrieve a specific key, I use the item method as shown here.

PS C:\Users\ed.WOODGROVE> $hash.Item("key2")

value2

PS C:\Users\ed.WOODGROVE> $hash.Item("key3")

value3

One of the things I like to do is to create an empty hash table and assign it to a variable. I will do this whether I am working in the Windows PowerShell console or using the Windows PowerShell ISE. To create an empty hash table, I use the @ sign followed by an opening and a closing brace. The three characters are assigned to a variable. This technique appears here:

$hash = @{}

An empty hash table object is created and is stored in the variable. This is verified by piping the object stored in the variable to the Get-Member cmdlet. The technique to retrieve the members appears here.

PS C:\Users\ed.WOODGROVE> $hash | Get-Member 

TypeName: System.Collections.Hashtable 

Name                           MemberType                             Definition

----                               ----------                                    ----------

Add                              Method                                     System.Void Add(System.Object key, System.Object value)

Clear                             Method                                     System.Void Clear()

Clone                            Method                                     System.Object Clone()

Contains                        Method                                     bool Contains(System.Object key)

ContainsKey                   Method                                     bool ContainsKey(System.Object key)

ContainsValue                Method                                     bool ContainsValue(System.Object value)

CopyTo                         Method                                     System.Void CopyTo(array array, int arrayIndex)

Equals                           Method                                     bool Equals(System.Object obj)

GetEnumerator              Method                                     System.Collections.IDictionaryEnumerator GetEnumerator()

GetHashCode                Method                                     int GetHashCode()

GetObjectData               Method                                     System.Void GetObjectData(System.Runtime.Serialization.SerializationInfo inf...

GetType                        Method                                     type GetType()

OnDeserialization           Method                                     System.Void OnDeserialization(System.Object sender)

Remove                         Method                                     System.Void Remove(System.Object key)

ToString                        Method                                     string ToString()

Item                              ParameterizedProperty               System.Object Item(System.Object key) {get;set;}

Count                            Property                                    System.Int32 Count {get;}

IsFixedSize                     Property                                    System.Boolean IsFixedSize {get;}

IsReadOnly                    Property                                    System.Boolean IsReadOnly {get;}

IsSynchronized               Property                                    System.Boolean IsSynchronized {get;}

Keys                              Property                                    System.Collections.ICollection Keys {get;}

SyncRoot                       Property                                    System.Object SyncRoot {get;}

Values                           Property                                    System.Collections.ICollection Values {get;}

After I have an empty hash table, I use the add method to populate the hash table with key/value pairs. The first thing I do is create an array of 100 integers by using the range operator. Next, I use the percentage sign (which is the alias for the ForEach-Object cmdlet) and call the add method. As previously discussed, the key property does not require quotation marks, but the value property does require them. The code to add 100 integers as key/value pairs to a hash table is shown in the following code:

1..100 | % { $hash.Add($_,"$_") }

To empty a hash table and permit reuse of the hash table, use the clear method. To verify that the hash table is empty, use the count property. The technique of clearing the hash table of data and verifying that it is empty is shown here:

PS C:\Users\ed.WOODGROVE> $hash.Clear()

PS C:\Users\ed.WOODGROVE> $hash.Count

0

Now that I have an empty hash table, I am going to populate it with the process ID and the process name of every running process on my system. Because it is likely that there could be more than one process with the same name (svchost, for example), I use the process ID (PID) as the key property and the name of the process as the associated value. The process information is easily obtained by using the Get-Process cmdlet.

Get-Process | % { $hash.Add($_.id,$_.name) }

When working with a hash table, I often need to look at only the keys. To get a listing of only the keys, use the keys property. This is illustrated in the following code where the keys property is used retrieve all of the keys and the Select-Object cmdlet (select is an alias for the Select-Object cmdlet) is used to limit the results to the first four keys:

PS C:\Users\ed.WOODGROVE> $hash.Keys | select -First 4

2620

1652

1412

4040

In the same manner, the values of a hash table can be obtained by using the values property. As you will remember, the value property of a hash table does not need to be unique. In the example of processes running on my computer, I know this is a case.

PS C:\Users\ed.WOODGROVE> $hash.count

64

PS C:\Users\ed.WOODGROVE> ($hash.Values | select -Unique | Measure-Object).count

50

The 64 running processes appear in Task Manager. As shown in the following figure, there are a number of duplicate processes.

Image of duplicate processes

The values property of the hash table returns all of the values that are associated with the key/value pairs. The count property tells me how many key/value pairs exist. By taking the collection of values and piping the results to the Select-Object cmdlet, I can use the unique switch to obtain only the unique items. I can then send the resulting collection of unique values to the Measure-Object cmdlet and choose the count property. The result tells me how many unique processes are running. The code and associated output to do this are shown here:

PS C:\Users\ed.WOODGROVE> $hash.count

64

PS C:\Users\ed.WOODGROVE> ($hash.Values | select -Unique | Measure-Object).count

50

I might like to see which processes have duplicates. In addition, I might like to see how many instances of each process are running. A reasonable list might include the top ten instances of these processes. To do this, I use the values property to return a list of all the values stored in the hash table, and I group them by value. Next, I sort them by the value of the count property, and choose the first 10 instances. (In the following command group, sort and select are aliases for Group-Object, Sort-Object, and Select-Object respectively). The command and associated output are shown here:

PS C > $hash.values | group -NoElement | sort count -Descending | select -First 10

Count    Name

-----      ----

   11      svchost

    3      iexplore

    2      csrss

    2      conhost

    1      IAStorDataMgrSvc

    1      SearchFilterHost

    1      sqlwriter

    1      SnagPriv

    1      dwm

    1      explorer

AC, that is all there is to using hash tables. Hash Table Week will continue tomorrow when I will talk about using hash tables to filter lists.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Thanks, Ed!

    This is an excellent example of the power of hashtables combined with cmdlets that sort, measure, select or make the data unique!

    And everything could really be done in a one-liner!

    Great!!!

    Klaus

  • Klaus, I am glad you enjoyed the article. I really appreciate all of your comments -- they make my day.

    ed