Hash tables in PowerShell are very useful and can be used for a bunch of things. Recently I had to use some code I found on StackOverflow to Merge hash tables. This post is about my experience and the really cool piece of code that iRon posted on StackOverFlow.
First I need to login to azure and find my application:
add-azurermaccount get-azurermresource
I see my resource in the Get-azureRmresource so now I know that I can query for it’s app settings using this command:
$myapp = Get-AzureRmWebAppSlot -resourcegroupname myresourcegroup -name myresourcename -slot production
This produces and object that contains all my web application settings in azure for my app in question. The item i want to work on is the .siteconfig.AppSettings
This portion of the object will have the properties of the appsettings in the azure blade as shown below:
PS C:\Users\me> $myApp.siteconfig.AppSettings
Name Value
WEBSITE_NODE_DEFAULT_VERSION 6.9.1
Now that I have the current version of what is in my application I now need to see what to do to put new settings in place and not wipe out any existing settings. The cmdlet to do the addition is Set-AzureRmWebAppSlot. After looking through the help I can see that I have a parameter that I can pass for the settings i want called -appSettings. It like most of the other settings require a hash table: [[-AppSettings] <Hashtable>]
So The $myApp.SiteConfig.Appsettings is a list:
$appSettings = $Myapp.siteconfig.appsettings &nbsp;$appsettings -is [pscustomobject] False &nbsp;$appsettings.gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True List`1 System.Object $appsettings -is [hashtable] False
This means I need to convert my object from List`1 to a hashtable so I’ll iterate through it and create a hashtable:
$appSettingsHash = @{} &nbsp;foreach($k in $appSettings) { $appSettingsHash[$k.name] = $k.value } &nbsp;$appsettingshash Name Value ---- ----- WEBSITE_NODE_DEFAULT_VERSION 6.9.1 &nbsp;$appsettingshash -is [hashtable] True
Ok now that I have my current settings in a hashtable I need to now work with entries that I want to add to a hashtable and then post it.
$appSettings ='{"AppSettings:testkey1": "45test","AppSettings:TestId": "This is a Test Key 28"}' $newAppSettings = $appSettings | convertfrom-json $newAppSettingsHash = @{} $newAppSettings.psobject.properties | ForEach-Object { $newAppSettingsHash[$_.Name] = $_.Value } $newappsettingsHash -is [hashtable] True
This is where the magic of iRon‘s script comes into play. Since I need to use this in a deployment from TFS I created the hashtable in Json Format first and then convert the Json format to a [hashtable]. Then I call iRon’s Script with the $newappSettingsHash and the $appsettingsHash. Now I have a merged hashtable that I can now update my application with.
Function Merge-Hashtables([ScriptBlock]$Operator) { $Output = @{} ForEach ($Hashtable in $Input) { If ($Hashtable -is [Hashtable]) { ForEach ($Key in $Hashtable.Keys) {$Output.$Key = If ($Output.ContainsKey($Key)) {@($Output.$Key) + $Hashtable.$Key} Else {$Hashtable.$Key}} } } If ($Operator) {ForEach ($Key in @($Output.Keys)) {$_ = @($Output.$Key); $Output.$Key = Invoke-Command $Operator}} $Output } $hashtable = $newAppSettingsHash, $appSettingsHash | Merge-Hashtables {$_[0]} $results = Set-AzureRmWebAppSlot -AppSettings $hashtable -name $website -ResourceGroupName $resourceGroup -slot $slot $r = $results.SiteConfig.AppSettings Write-Output $r
The really cool thing about the Merging of the hashtables function is that you can merge more than 2 hash tables. See this comment from iRon about how it works:
Full code for this merge hashtable function against a azure application is below:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param($websitename = 'TEst' ,$resourceGroup = 'SchuTest',$slot = 'production', $appSettings ='{"AppSettings:testkey1": "45test","AppSettings:TestId": "This is a Test Key 28"}') | |
#https://stackoverflow.com/questions/8800375/merging-hashtables-in-powershell-how | |
Function Merge-Hashtables([ScriptBlock]$Operator) { | |
$Output = @{} | |
ForEach ($Hashtable in $Input) { | |
If ($Hashtable -is [Hashtable]) { | |
ForEach ($Key in $Hashtable.Keys) {$Output.$Key = If ($Output.ContainsKey($Key)) {@($Output.$Key) + $Hashtable.$Key} Else {$Hashtable.$Key}} | |
} | |
} | |
If ($Operator) {ForEach ($Key in @($Output.Keys)) {$_ = @($Output.$Key); $Output.$Key = Invoke-Command $Operator}} | |
$Output | |
} | |
try { | |
foreach($website in $websiteName) | |
{ | |
ConvertFrom-Json $appSettings –ErrorAction Stop | |
#it is expected that the app settings is a string representation of a hashtable that is writtin in Json. So that it can be converted to a powershell hashtable during runtime | |
$newAppSettings = $appSettings | convertfrom-json | |
$newAppSettingsHash = @{} | |
$newAppSettings.psobject.properties | ForEach-Object { $newAppSettingsHash[$_.Name] = $_.Value } | |
$Application = get-azurermwebappslot –Name $website –ResourceGroupName $resourceGroup –Slot $slot | |
$ExistingSettings = $Application.siteconfig.AppSettings | |
$appSettingsHash = @{} | |
foreach($k in $ExistingSettings) | |
{ | |
$appSettingsHash[$k.name] = $k.value | |
} | |
#https://stackoverflow.com/questions/8800375/merging-hashtables-in-powershell-how | |
$hashtable = $newAppSettingsHash, $appSettingsHash | Merge-Hashtables {$_[0]} | |
$results = Set-AzureRmWebAppSlot –AppSettings $hashtable –name $website –ResourceGroupName $resourceGroup –slot $slot | |
$r = $results.SiteConfig.AppSettings | |
Write-Output $r | |
} | |
} | |
catch | |
{ | |
Write-Error "$appsettings must be in JSON format" | |
} |
I hope that when you need to merge hashtables this article makes it a bit easier for you.
Until then keep scripting
thom
One thought on “Merging hashtables”