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

}