Americas

  • United States

Asia

jonathan_hassell
Contributing Writer

More PowerShell: Hash tables

feature
May 05, 20169 mins
Data CenterEnterprise Applications

Using arcane text-based syntax to achieve miraculous results

In this next installment of my ongoing PowerShell series, I want to focus on putting PowerShell objects to work for you. Let me warn you in advance, however: Put on your advanced thinking caps for this piece, especially if you are a non-programmer or non-developer and are used to pointing at things and clicking them once or twice to accomplish some tasks. I’m going to get abstract with you here but, as far as I know, there is no way around it.

The subject? Hash tables. These are very useful tools to have in your arsenal. It just takes a while to both (a) understand them and their use fully and (b) wrap your head around the extremely funky syntax that they use. Really, the syntax is unforgiveable. I’m going to try to simplify things as much as possible.

Hash tables: The basics and fundamentals

Hash tables are a fancy way of saying “A table full of single pieces of information many times over.” Those single pieces of information are known as name-value pairs, or key-value pairs as you might sometimes see them called. These pairs store a single piece of data; the key is the descriptive word about the data and the value is the actual piece of data.

A common example of key-value pairs are a list of American states and their capitals. We might call our key-value pair table “StateCapitals,” for instance, and then within that table, each state would be the key, and each state’s capital would be the value. We can create a sample table just to demonstrate how this would look.

StateCapitals

Key Value
North Carolina Raleigh
California Sacramento
New York Albany
Florida Tallahassee
Texas Austin

And so on. Again, in a table for state capitals, the key would describe the state and the value would describe the capital, the thing that is in question.

Another example could be NFL teams and their mascots.

NFLMascots

Key Value
Carolina Panther
New England Patriot
Seattle Seahawk
Dallas Cowboy
Atlanta Falcon

Again, in a table for professional football team mascots, the key would describe the team and the value would describe the actual mascot, the thing that is in question.

A hash table is actually just a table full of those key value pairs. You can start off a hash table as the value of a variable, and then you simply place an @ sign, a left curly brace, and then use ‘”key1″ = “value1”; “key2 = “value2″‘ and so on. Let’s use both of the above “spelled-out” tables as examples.

$StateCapitals = @{"North Carolina" = "Raleigh"; "California" = "Sacramento"; "New York" = "Albany"; "Florida" = "Tallahassee"; "Texas" = "Austin"}

$NFLMascots = @{"Carolina" = "Panther"; "New England" = "Patriot"; "Seattle" = "Seahawk"; "Dallas" = "Cowboy"; "Atlanta" = "Falcon"}

Enter those into your PowerShell window to get a feel for how they work. To check on them, just enter the variable’s name at the prompt to display its value, which, if you typed correctly, should be the hash table. This shows an example of this on my system:

PowerShell hash tables fig 1

Converting unexpected output into something useful with hash tables

That’s how you create a hash table at its most basic. Hash tables are important because some PowerShell commands will understand hash tables as values for their parameters, and one of the most common PowerShell commands you would use in this scenario is ‘Select-Object.’ But when you’re using ‘Select-Object’ to pick properties to display, what happens if the content of those properties in the output isn’t what you expected? Or what if the name of the property is one thing, but the command to which you want to pipe that output expects the same content to be called something else entirely? In that case, you would use hash tables along with ‘Select-Object.’

‘Select-Object’ accepts hash tables formatted with two specific key-value pairs. Well, more specifically, it needs two keys to be present. One key is ‘Name,’ and the value of ‘Name’ is used for the column header. You can use this to rewrite the names of column headers to be something else. The other key ‘Select-Object’ needs is called ‘Expression’ — and the value of that key needs to be a script or PowerShell code. It can be a simple script or simple code, within curly braces — ‘{‘and ‘}’ — but that is what ‘Select-Object’ expects there.

For the purposes of our piece here today, I’ll talk about just one aspect of using hash tables with ‘Select-Object’– the ability to rewrite column names. Let’s take a simple example. If you run ‘Get-Process’ from the PowerShell console, you get a nice table with handles, a bunch of statistics and a column header called ‘ProcessName.’ But what if you want to rewrite that table so it calls that column ‘The Name of the Process’ rather than ‘ProcessName’?

You could create a hash table to do just that. That hash table is going to be built like this: First, you use ‘Select-Object’ because, well, that’s the command. Then you use the ‘@’ sign, which signals to PowerShell that you intend to create a hash table. Then a left curly brace ‘{‘ begins the contents of the table. Then, you type in the key ‘Name’ — remember that has to be the name of the key when you use a hash table with ‘Select-Object,’ so hard-code that into your memory at this point. Next, use an ‘=’ and then add the name of the column you wish to use, enclosed in quotation marks, and end with a semicolon (‘;’).

So far that looks like this:

Select-Object @{Name = "The Name of the Process";

Next up, we add the expression. It’s called ‘Expression’ — and that’s another hard-coding thing to remember here when hash tables are used with ‘Select-Object.’ Another equals sign goes in next, followed by a left curly brace — ‘{‘ — to signify the beginning of a PowerShell code expression.

Next, in this case, we can use the “that thing” notation (‘$_’) that I covered in a previous installment of this series (specifically in the story about creating scripts and loops), because it represents the object in the pipeline — which for us, in this example, is the output of ‘Get-Process.’

To access a property of ‘Get-Process,’ we simply add a dot (‘.’) and then the name of the property, which in this case is the original column header, ‘ProcessName.’ We then add a right curly brace to signify the end of the expression, and then a final right curly brace to signal the end of the hash table itself. That leaves us with this final ‘Select-Object’ statement:

Select-Object @{Name = "The Name of the Process"; Expression = {$_.ProcessName}}

Now just add the original ‘Get-Process’ to the front of that and you’ll be golden:

Get-Process | Select-Object @{Name = "The Name of the Process"; Expression = {$_.ProcessName}}

This shows what that command returns.

PowerShell hash tables Fig 2

You have renamed the column totally in the pipeline, without exporting it to a file and editing the resulting file. Way to transform! You’re a superhero.

Using multiple properties with hash tables

You can also use multiple properties with ‘Select-Object.’ For instance, we can just include the ‘Id’ property with our table to get both the process ID and the transformed column. Just separate out the properties in the ‘Select-Object’ command with commas but no spaces.

Get-Process | Select-Object Id,@{Name = "The Name of the Process"; Expression = {$_.ProcessName}}

And that results in the following:

PowerShell hash tables figure 3

And you might already know how to fix that funky off-centered formatting. If you do not understand, that’s fine — there is a built-in PowerShell command called ‘Format-Table’ that does a nice job of preparing all of the output into a nice, neat, easily readable table:

Get-Process | Select-Object @{Name = "The Name of the Process"; Expression = {$_.ProcessName}} | Format-Table -AutoSize

You can also use multiple hash tables. For instance, let’s rewrite that ID column to call it “Process ID” and keep the other column renamed, too.

Get-Process | Select-Object @{Name = "Process ID"; Expression = {$_.Id}},@{Name = "The Name of the Process"; Expression = {$_.ProcessName}} | Format-Table -AutoSize

We can see how that comes out:

PowerShell hash tables figure 4

Pretty cool, huh? And now you see what I mean when I say the syntax is unforgiveable. But that is how PowerShell works, at least as the state of its art right now.

A practical application of hash tables: Creating Active Directory accounts from a list

When might this be useful, however? There are some commands, particularly those that import data, which need values named certain ways. But sometimes you might have data that you need to import into those commands that is named in a different way. For instance, let’s say you have a file that has a list of new interns who need accounts on your Active Directory domain. This might be a CSV feed from your hiring system, so it looks something like this:

First Name,Last Name,Logon Name,Division

Shelly,Johnson,sjohnson,Administrative

Brian,Smith,bsmith,Finance

Bridget,Williams,bwilliams,Communications

But when you go to try to create a new Active Directory Domain Services user account with PowerShell, you are confronted with the following problem: For the command that you will use, ‘New-ADUser,’ there are parameters for GivenName and Surname and SamAccountName and Department. That’s all well and good, but your file has data for First Name, Last Name, Logon Name and Division.

We’ll use a hash table, then, with ‘Select-Object’ to take care of renaming the headers in your CSV file to the names that ‘New-ADUser’ is expecting. Finally, we’ll pipe that into ‘New-ADUser’ to finish up the job.

Import-CSV c:interns.csv | Select-Object @{Name="Surname";Expression={$_."Last Name"}}, @{Name="GivenName";Expression={$_."First Name"}},

@{Name="SamAccountName";Expression={$_."Logon Name"}},

@{Name="Department";Expression={$_."Division"}}

The last word

That was pretty in-the-weeds, wasn’t it? But it’s a very powerful capability and one you will surely use as you step into more advanced scripting and administration scenarios. And it shows off just how useful PowerShell output as objects can be.