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:
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”