A hash table is an array of key/value pairs, along with accompanying functions for
readily accessing or modifying values by way of their corresponding keys.
Creating and Populating a Hash Table
Here is the PowerShell syntax for initializing an empty hash table object:
$myHashTable = @{}
We add elements to the hash table quite easily via several different mechanisms.
$key = "key 1" $value = "value 1" $myHashTable.add($key,$value) $myHashTable.add("key 2", "value 2")
Here is what the resulting hash table looks like:
PS C:\> $myHashTable Name Value ---- ----- key 2 value 2 key 1 value 1
Alternatively, we could have populated the hash table at the time that we created it via the following syntax:
$myHashTable2 = @{ 100 = "One Hundred" 1000 = "One Thousand" 10000 = "Ten Thousand" }
It should be noted that order is not necessarily preserved in a hash table:
PS C:\> $myHashTable2 Name Value ---- ----- 1000 One Thousand 10000 Ten Thousand 100 One Hundred
There is, however, a syntax for constructing a hash table of type [ordered] if that is needed:
PS C:\> $myHashTable2 = [ordered]@{ 100 = "One Hundred" 1000 = "One Thousand" 10000 = "Ten Thousand" } PS C:\> $myHashTable2 Name Value ---- ----- 100 One Hundred 1000 One Thousand 10000 Ten Thousand
Accessing Hash Table Values
Accessing the values of hash table entries by means of the keys is pretty straightforward, and multiple syntaxes are provided for doing so.
PS C:\> $myHashTable["key 1"] value 1 PS C:\> $myHashTable."key 2" value 2 PS C:\> $myHashTable2.1000 One Thousand
I should note here, however, that the [] syntax changes behavior when the hash table is defined as an ordered hash table (as in the way in which I have redefined $myHashTable2 in these examples). In that case, the arguments in square brackets are passed as an array index rather than a key.
PS C:\> $myHashTable2[100] PS C:\> $myHashTable2[0] One Hundred
Modifying Hash Table Entries
blah
Silly Hash Table Tricks
Keep in mind that key names are simply strings, and since PowerShell strings by default use UTF-16 encoding, we are squarely in the world of Unicode, which can, in turn, include Emoji.
PS C:> $myHashTable = @{ "💩" = "Poo Emoji" "🎼" = "Treble Clef" "⏰" = "Clock" "😁" = "Laughing Emoji" } PS C:> $myHashTable."🎼" Treble Clef PS C:> $myHashTable."💩" Poo Emoji
I don’t know how useful this particularly is, but it amuses me. It is somewhat reminiscent of the ability to use Unicode strings to define variable names in Apple’s programming language, Swift.
Here is a more practical example in which the hash table is used literally as a dictionary lookup table, translating Korean words (rendered in Hangul) to English.
PS C:\> $myHashTable = @{ 가다 = "to go" 웃다 = "to come" 먹다 = "to eat" } PS C:\> $myHashTable.가다 to go
Creating Calculated Properties
When using Select-Object, Format-List, or Format-Table, it is possible to use hash tables to dynamically rename attributes or to calculate synthetically-generated attributes on the fly. For example, running the Get-ChildItem command to examine filesystem objects results in the permissions of each object being returned in an attribute called “Mode”. We can use a hash table to rewrite this attribute name on the fly as something more descriptive.
PS C:\> Get-ChildItem | where {$_.Name -like "Users"} | select Mode,Name | ft -AutoSize Mode Name ---- ---- d-r-- Users PS C:\> $property = @{ name = "Permissions" expression = {$_.Mode} } PS C:\> Get-ChildItem | where {$_.Name -like "Users"} | select $property,Name | ft -AutoSize Permissions Name ----------- ---- d-r-- Users
Of course, this particular sort of application of hash tables in PowerShell is more commonly seen with the hash table defined in-line. However, that approach somewhat degrades readability of the script.
PS C:\> Get-ChildItem | where {$_.Name -like "Users"} | select @{name = "Permissions"; expression = {$_.Mode}},Name | ft -AutoSize Permissions Name ----------- ---- d-r-- Users
We’ve shown how to rename a property on the fly, but how about dynamically generating calculated attributes? For example, when we run Get-ChildItem on files, the size is returned, in bytes, in an attribute called “Length”.
PS C:\Windows\System32> Get-ChildItem win*.exe | ft Name,Length -AutoSize Name Length ---- ------ wininit.exe 129024 winload.exe 634272 winlogon.exe 455680 winresume.exe 546656 winrs.exe 46080 winrshost.exe 23040 winver.exe 80384
What if we instead want the size to be shown in kilobytes, with the name of the property modified appropriately to reflect this?
PS C:\Windows\System32> $size = @{ name = "Size (KB)" expression = {($_.Length)/1KB} } PS C:\Windows\System32> Get-ChildItem win*.exe | ft Name,$size -AutoSize Name Size (KB) ---- --------- wininit.exe 126 winload.exe 619.40625 winlogon.exe 445 winresume.exe 533.84375 winrs.exe 45 winrshost.exe 22.5 winver.exe 78.5
Splatting PowerShell Parameters With Hash Tables
It is possible to pass collections of parameters to PowerShell cmdlets in the form of hash tables. This feature, introduced in PowerShell v2, is called “splatting.”
PS C:> $myColors = @{
ForegroundColor = "Cyan"
BackgroundColor = "Black"
}
PS C:> Write-Host "Hello" @myColors
Hello
You can mix in “splatted” parameters with parameters passed via normal means, as well as passing mulitple hash tables, all provided that none the parameters passed conflict.
PS C:> $sep = @{
Separator = "<---->"
}
PS C:> Write-Host "Thing 1","Thing 2","Thing 3" @sep @myColors -NoNewline ; Write-Host "!"
Thing 1<---->Thing 2<---->Thing 3!
Hash Table Example: Mapping O365 SKUs to License Names
blah
Note that this list is by no means complete but rather reflects what I see in the tenant that I administer. It even includes SKUs that have since been deprecated and replaced by other SKUs. This hash table includes both SKUs and services, and the entries are presented in no particular order.
$names = @{ "STANDARDWOFFPACK_STUDENT" = "Office 365 A1 for students" "STANDARDWOFFPACK_IW_STUDENT"="Office 365 A1 Plus for students" "PROJECTONLINE_PLAN_1_FACULTY"="Project Online Premium without Project Client for faculty" "EXCHANGEENTERPRISE_FACULTY"="Exchange Online (Plan 2) for faculty" "PROJECTONLINE_PLAN_2_FACULTY"="Project Online with Project Pro for Office 365 for Faculty" "STANDARDWOFFPACK"="Microsoft Office 365 Plan E2" "OFFICESUBSCRIPTION_FACULTY"="Office 365 ProPlus for faculty" "OFFICESUBSCRIPTION_STUDENT"="Office 365 ProPlus for students" "STANDARDWOFFPACK_FACULTY"="Office 365 A1 for faculty" "ATP_ENTERPRISE_FACULTY" = "Exchange Online Advanced Threat Protection for Faculty" "RMS_S_ENTERPRISE"="Azure Rights Management" "OFFICE_FORMS_PLAN_2"="Microsoft Forms (Plan 2)" "PROJECTWORKMANAGEMENT"="Microsoft Planner" "SWAY"="Sway" "INTUNE_O365"="Mobile Device Management for Office 365" "YAMMER_EDU"="Yammer for Academic" "SHAREPOINTWAC_EDU" = "Office Online for Education" "MCOSTANDARD" = "Skype for Business Online (Plan 2)" "SHAREPOINTSTANDARD_EDU" = "SharePoint Plan 1 for EDU" "EXCHANGE_S_STANDARD" = "Exchange Online (Plan 1)" "OFFICESUBSCRIPTION" = "Office 365 ProPlus" "EXCHANGE_S_FOUNDATION" = "Exchange Foundation (?)" "SHAREPOINT_PROJECT_EDU" = "Project Online Service for Education" "SHAREPOINTENTERPRISE_EDU" = "SharePoint Plan 2 for EDU" "EXCHANGE_S_ENTERPRISE" = "Exchange Online (Plan 2)" "PROJECT_CLIENT_SUBSCRIPTION" = "Project Online Desktop Client" "ONEDRIVESTANDARD" = "OneDrive for Business (Plan 1)" "FLOW_O365_P2" = "Flow for Office 365" "POWERAPPS_O365_P2" = "PowerApps for Office 365" "Deskless" = "Microsoft StaffHub" "TEAMS1" = "Microsoft Teams" "STREAM_O365_E3" = "Microsoft Stream for O365 E3 SKU" "EMS" = "Enterprise Mobility + Security E3" "RMS_S_PREMIUM" = "Azure Information Protection Plan 1" "INTUNE_A" = "Intune A Direct" "AAD_PREMIUM" = "Azure Active Directory Premium Plan 1" "MFA_PREMIUM" = "Azure Multi-Factor Authentication" "POWER_BI_STANDARD_FACULTY" = "Power BI (free) for faculty" "BI_AZURE_P0" = "Power BI (free)" "ATP_ENTERPRISE" = "Advanced Threat Protection" "MCOMEETADV_FACULTY" = "Skype for Business PSTN Conferencing for faculty" "MCOMEETADV" = "Skype for Business PSTN Conferencing" "SCHOOL_DATA_SYNC_P1" = "School Data Sync (Plan 1)" "FORMS_PLAN_E1" = "Microsoft Forms (Plan E1)" "PROJECTPREMIUM_FACULTY" = "Project Online Premium for faculty" "PROJECTESSENTIALS_FACULTY" = "Project Online Essentials for faculty" "PROJECT_ESSENTIALS" = "Project Online Essentials" "BPOS_S_TODO_2"="To-Do (Plan 2)" "AAD_BASIC_EDU"="Azure Active Directory Basic for Edu" "ADALLOM_S_DISCOVERY" = "Cloud App Security Discovery" "POWER_BI_PRO_FACULTY" = "Power BI Pro for faculty" "PROJECTPROFESSIONAL_FACULTY" = "Project Online Professional for faculty" }
Let’s say that we want to use this hash table to show the friendly names for all of the SKUs returned by Get-MsolAccountSku:
PS C:> $skus=Get-MsolAccountSku PS C:> foreach ($sku in $skus){ $skupart = $sku.SkuPartNumber Write-Host ("{0,-28} {1,-40}" -f $skupart,$names.Item($skupart)) } PROJECTESSENTIALS_FACULTY Project Online Essentials for faculty MCOMEETADV_FACULTY Skype for Business PSTN Conferencing for faculty ATP_ENTERPRISE_FACULTY Exchange Online Advanced Threat Protection for Faculty POWER_BI_STANDARD_FACULTY Power BI (free) for faculty STANDARDWOFFPACK_STUDENT Office 365 A1 for students POWER_BI_PRO_FACULTY Power BI Pro for faculty STANDARDWOFFPACK_IW_STUDENT Office 365 A1 Plus for students EXCHANGEENTERPRISE_FACULTY Exchange Online (Plan 2) for faculty PROJECTPROFESSIONAL_FACULTY Project Online Professional for faculty EMS Enterprise Mobility + Security E3 OFFICESUBSCRIPTION_FACULTY Office 365 ProPlus for faculty OFFICESUBSCRIPTION_STUDENT Office 365 ProPlus for students STANDARDWOFFPACK_FACULTY Office 365 A1 for faculty PROJECTPREMIUM_FACULTY Project Online Premium for faculty
Suppose that we no want to take a look at all of the services under a specific SKU, say the one for EMS:
PS C:\Working\Scripts\glenmartin\lice> foreach ($service in $skus[9].ServiceStatus) { $ServName = $names.Item($service.ServicePlan.ServiceName) Write-Host ("{0} {1,-25} {2,-40} {3,-15}" -f "`t",$service.ServicePlan.ServiceName,$ServName,$service.ProvisioningStatus) } EXCHANGE_S_FOUNDATION Exchange Foundation (?) Success ADALLOM_S_DISCOVERY Cloud App Security Discovery Success RMS_S_PREMIUM Azure Information Protection Plan 1 Success INTUNE_A Intune A Direct Success RMS_S_ENTERPRISE Azure Rights Management Success AAD_PREMIUM Azure Active Directory Premium Plan 1 Success MFA_PREMIUM Azure Multi-Factor Authentication Success
(Note that I have a question mark in the Exchange Foundation service name since Microsoft does not document this one at all, nor does this service get listed in the web interface.)
For More Information
-
- Powershell: Everything you wanted to know about hashtables | Kevin Marquette on PowerShell Theory
- About Hash Tables | Microsoft Docs
- Microcode: PowerShell Scripting Tricks: The Joy of using Hashtables with Windows PowerShell | Media And Microcode
- New-Object PSObject –Property [HashTable] | PowerShell Team Blog
- Learn the Basics of PowerShell Hash Tables – Hey, Scripting Guy! Blog
- Easily Create a PowerShell Hash Table – Hey, Scripting Guy! Blog
- Automatically Create a PowerShell Hash Table – Hey, Scripting Guy! Blog
- Dealing with PowerShell Hash Table Quirks – Hey, Scripting Guy! Blog
- PowerTip: Find Value from PowerShell Hash Table – Hey, Scripting Guy! Blog
- Use PowerShell to Create Ordered Dictionary – Hey, Scripting Guy! Blog
- ConvertTo-OrderedDictionary – Hey, Scripting Guy! Blog
- Create a Hash Table in PowerShell that Contains Hash Tables – Hey, Scripting Guy! Blog
- Slice and Dice with Hash Tables in PowerShell | MCP Mag
- Windows PowerShell: Splatting | TechNet Magazine – Microsoft
- PowerShell splatting – Microsoft Docs
- Use Splatting to Simplify Your PowerShell Scripts – Hey, Scripting Guy! Blog
- Using PowerShell’s Calculated Properties | MCP Mag