functions/object-properties.ps1


function get-propertynames($obj) {
    Measure-function "$($MyInvocation.MyCommand.Name)" {    
        if ($obj -is [System.Collections.IDictionary]) {
            return $obj.keys
        }
        return $obj.psobject.Properties | select -ExpandProperty name
    }
}

function add-properties(
    [Parameter(Mandatory=$true, ValueFromPipeline = $true)] 
    $object,
    [Parameter(Mandatory=$true)]
    $props, 
    [switch][bool] $ifNotExists, 
    [switch][bool] $merge, 
    $exclude = @()
) {
    Measure-function  "$($MyInvocation.MyCommand.Name)" {
        foreach($prop in get-propertynames $props) {
            if ($prop -notin $exclude) {
                try {
                    $r = add-property $object -name $prop -value $props.$prop -ifnotexists:$ifnotexists -merge:$merge
                } catch {
                    throw "failed to add property '$prop' with value '$props.$prop': $($_.Exception.Message)"
                }
            }
        }
        return $object
    }
}

# function add-property {
# [CmdletBinding()]
# param(
# [Parameter(ValueFromPipeline = $true, Position=1)] $object,
# [Parameter(Mandatory=$true,Position=2)] $name,
# [Parameter(Mandatory=$true,Position=3)] $value,
# [switch][bool] $ifNotExists,
# [switch][bool] $overwrite,
# [switch][bool] $merge
# )
# # Measure-function "$($MyInvocation.MyCommand.Name)" {
# try {
# if ($null -ne $object.$name) {
# if ($merge -and $object.$name -is [System.Collections.IDictionary] -and $value -is [System.Collections.IDictionary]) {
# $r = add-properties $object.$name $value -ifNotExists:$ifNotExists -merge:$merge
# return $object
# }
# elseif ($ifNotExists) {
# return
# }
# elseif ($overwrite) {
# $object.$name = $value
# }
# else {
# throw "property '$name' already exists with value '$($obj.$name)'"
# }
# }
# if ($object -is [System.Collections.IDictionary]) {
# $object[$name] = $value
# }
# else {
# throw "optimization - only support hashtabes"
# $null = $object | add-member -name $name -membertype noteproperty -value $value
# #$object.$name = $value
# }

# return $object
# } catch {
# throw
# }
# # }
# }

function ConvertTo-Hashtable([Parameter(ValueFromPipeline=$true)]$obj, [switch][bool]$recurse) {
    Measure-function  "$($MyInvocation.MyCommand.Name)" {

        $object =$obj
        if (!$recurse -and ($object -is [System.Collections.IDictionary] -or $object -is [array])) {
            return $object
        }
 
        if($object -is [array]) {
            if ($recurse) {
                for($i = 0; $i -lt $object.Length; $i++) {
                    $object[$i] = ConvertTo-Hashtable $object[$i] -recurse:$recurse
                }
            }
            return $object
        } 
        elseif ($object -is [System.Collections.IDictionary] -or  $object -is [System.Management.Automation.PSCustomObject] -or $true) {
            $h = @{}
            $props = get-propertynames $object
            foreach ($p in $props) {
                if ($recurse) {
                    $h[$p] = ConvertTo-Hashtable $object.$p -recurse:$recurse
                } else {
                    $h[$p] = $object.$p
                }
            }
            return $h
        } else {
            throw "could not convert object to hashtable"
            #return $object
        }
    }
    
}


function ConvertTo-Object([Parameter(ValueFromPipeline=$true)]$hashtable, $recurse) {    
    Measure-function  "$($MyInvocation.MyCommand.Name)" {
        if ($hashtable -is [hashtable]) {
            $copy = @{}
            $copy += $hashtable
            foreach($key in = get-propertynames $hashtable) {
                $val = $hashtable[$key]
                $obj = ConvertTo-Object $val -recurse $recurse
                $copy[$key] = $obj            
            }
            return New-Object -TypeName PSCustomObject -Property $copy 
        } 
        elseif ($hashtable -is [System.Management.Automation.PSCustomObject]) {
            $copy = @{}
            foreach($key in get-propertynames $hashtable) {
                $val = $hashtable.$key
                $obj = ConvertTo-Object $val -recurse $recurse
                $copy[$key] = $obj            
            }
            return New-Object -TypeName PSCustomObject -Property $copy 
        } 
        elseif ($hashtable -is [Array]) {        
            return $hashtable
        }
        else {
            return $hashtable
        }   
    }
}


function copy-hashtable($hash) {
    Measure-function  "$($MyInvocation.MyCommand.Name)" {

        $new = @{}
        foreach($key in get-propertynames $hash) {
            if ($hash.$key -is [System.Collections.IDictionary]) {
                $new.$key = copy-hashtable $hash.$key
            } else {
                $new.$key = $hash.$key
            }   
        }

        return $new
    }
}