0

I'm trying to merge two objects in PowerShell, but I seem to be stuck in a recursive loop. Arrays should be appended from source to target, and the rest should be replaced. We should also go as far down in the structure as we can to avoid replacing data when not needed. Can anyone spot something wrong? It seems to be line 27 that's causing it.

function Merge-Objects {
    Param(
        # Do not append to array. Replace it instead.
        [bool]$replaceArrays = $false,

        # Source object (the data that will be merged)
        [Parameter(Mandatory = $true)]
        [object]$source,

        # Target object (where the data will be merged)
        [Parameter(Mandatory = $true)]
        [object]$target
    )


    ForEach ($child in $source.PSObject.Properties)
    {
        # Set basic variables
        $childName  = $child.Name
        $childValue = $child.Value
        $childType  = $source.$childName.GetType().Name

        # If the item is a table, iterate further
        If ($childType -eq 'Hashtable' -and `
            $target.${childName}.GetType().Name -eq 'Hashtable')
        {
            $target.$childName = Merge-Objects -source $childValue -target $target.$childName
        }

        # If the object is an array, append or replace depending on parameters
        ElseIf ($childValue        -is [array] -and `
                $target.$childName -is [array] -and `
                $replaceArrays     -eq $false)
        {
            $target.$childName = $source.$childName + $target.$childName
        }

        # If none of the above, then replace/add the item
        Else
        {
            $target.$childName = $childValue
        }
    }

    Return $target
}


$object1 = [PSCustomObject]@{
  value1 = "test1"
  value3 = @{
    test2 = "test3"
    array = @( "asd3" )
  }
  array = @(
    "hejsan"
    @{
      asd1 = "value1"
      anotherarray = @( "test1" )
    }
  )
}


$object2 = [PSCustomObject]@{
  value1 = "value3"
  value2 = "test2"
  value3 = @{
    test1 = "test1"
    test2 = "test2"
    array = @( "asd2" )
  }
  array = @(
    "svejsan"
    @{
      asd2 = "value2"
      anotherarray = @( "test1" )
    }
  )
}

# Merge the objects recursively
Merge-Objects -source $object1 -target $object2

I tried to solve this recursive loop by not using the function recursively, but I can't make it work either. The array parts seems to work at least.

All the other code snippets found on StackOverflow had all had the problem of not recursing downwards and appending to arrays as far down as possible (in my example the array in value3 is not appended).

3
  • I currently don't have the time to look in detail, but I've written a similar function, that treats arrays a bit different. It might still help you to look at the code: stackoverflow.com/a/72521534/7571258 Commented Aug 22, 2023 at 15:44
  • The problem is you can't just pass the hashtable property values into your recursive call - you need to write some code that iterates over the keys and passes each pair into merge-objects. At the moment your recursive call iterates over the properties of a hashtable, not the keys. The problematic property is SyncRoot which itself is a hashtable., so that makes another call to Merge-Objects with the syncroot values, and that hashtable itself has a syncroot property so your recursion goes into a tailspin that only ends when you run out of recursion juice... Commented Aug 22, 2023 at 19:27
  • @mclayton Thank you so much for your answer! You pointed me in the right direction. My solution was to convert any non-hashtable objects to a hashtable, and then iterate over its keys instead of its properties (which you can do with hashtables and not with a pscustomobject or a httpresponseobject). Commented Aug 24, 2023 at 13:36

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.