Functions/object.ps1

function Merge-Object(
    [Parameter(Mandatory = $true)]
    [object]$base,

    [Parameter(Mandatory = $true)]
    [object]$additional,

    [ValidateSet("union", "overwrite")]
    [string]
    # array merge type: union, or overwrite. Default is union.
    $arrayMergeType = 'union'
) {
    $baseItem = Set-InnerProperties $base $additional
    return $baseItem
}

function Get-PropertyName($property) {
    if ($property -isnot [string]) {
        return $property.PSObject.properties.name
    }
    return $property.toString()
}

function Set-InnerProperties($base, $additional) {
    $baseItem = ($base).PsObject.Copy()
    
    $additional.psobject.Properties | ForEach-Object {
        $value = $_.Value
        if ($arrayMergeType -ceq 'union' -and $_.Value -is [system.array]) {
            $defaultValue = $baseItem | select -ExpandProperty $_.Name -ErrorAction SilentlyContinue
            $excludeItems = $additional | select -ExpandProperty "skip$($_.Name)" -ErrorAction SilentlyContinue
            $value = @(Merge-Array $defaultValue $_.Value $excludeItems)
        }
        elseif ($_.Value -is [psobject]) {
            $defaultValue = $baseItem | select -ExpandProperty $_.Name -ErrorAction SilentlyContinue
            $value = Set-InnerProperties $defaultValue $_.Value
        }
        $baseItem | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $value -force
    }
    return $baseItem
}