public/Merge-Hashtables.ps1
function Merge-Hashtables { [cmdletbinding()] Param ( # First hashtable to merge, this will have priority [hashtable] $primary, # second hashtable to merge [hashtable] $secondary ) # If in debug mode, show the function currently in #Write-Log -IfDebug -Message $("***** {0} *****" -f $MyInvocation.MyCommand) # Craete an array of types that can be merged. # Hashtables and Dictionaries can be merged $types = @( "Hashtable" "Dictionary``2" ) if($primary.Count -eq 0){ return $secondary } if($secondary.Count -eq 0) { return $primary } $primaryCopy = $primary.Clone() $secondaryCopy = $secondary.Clone() #check for any duplicate keys $duplicates = $primaryCopy.keys | Where-Object {$secondaryCopy.ContainsKey($_)} if ($duplicates) { foreach ($key in $duplicates) { # if the item is a hashtable then call this function again $primaryCopy.$key = if ($primaryCopy.$key.Count -gt 0){$primaryCopy.$key} else { @{} } $secondaryCopy.$key = if ($secondaryCopy.$key.Count -gt 0){$secondaryCopy.$key} else { @{} } if ($types -contains $primaryCopy.$key.gettype().name -and $types -contains $secondaryCopy.$key.gettype().name) { # set the argument hashtable $splat = @{ primary = $primaryCopy.$key secondary = $secondaryCopy.$key } $primaryCopy.$key = Merge-Hashtables @splat } # if the key is an array merge the two items if ($primaryCopy.$key.GetType().Name -eq "Object[]" -and $secondaryCopy.$key.GetType().name -eq "Object[]") { $result = @() # Because an array can contain many different types, need to be careful how this information is merged # This means that the normal additional functions and the Unique parameter of Select will not work properly # so iterate around each of the two arrays and add to a result array foreach ($arr in @($primaryCopy.$key, $secondaryCopy.$key)) { # analyse each item in the arr foreach ($item in $arr) { # Switch on the type of the item to determine how to add the information switch ($item.GetType().Name) { "Object[]" { $result += , $item } # If the type is a string make sure that the array does not already # contain the same string "String" { if ($result -notcontains $item) { $result += $item } } # For everything else add it in default { $result += $item } } } } # Now assign the result back to the primary array $primaryCopy.$key = $result } #force primary key, so remove secondary conflict $secondaryCopy.Remove($key) } } #join the two hash tables and return to the calling function $primaryCopy + $secondaryCopy } |