PSDataKit.psm1

# Implement your module commands in this script.


# Export only the functions using PowerShell standard verb-noun naming.
# Be sure to list each exported functions in the FunctionsToExport field of the module manifest file.
# This improves performance of command discovery in PowerShell.




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
    }

    #check for any duplicate keys
    $duplicates = $primary.keys | Where-Object {$secondary.ContainsKey($_)}

    if ($duplicates) {
        foreach ($key in $duplicates) {

                # if the item is a hashtable then call this function again
                $primary.$key = if ($primary.$key.Count -gt 0){$primary.$key} else { @{} }
                $secondary.$key = if ($secondary.$key.Count -gt 0){$secondary.$key} else { @{} }

                if ($types -contains $primary.$key.gettype().name -and
                    $types -contains $secondary.$key.gettype().name) {

                    # set the argument hashtable
                    $splat = @{
                        primary = $primary.$key
                        secondary = $secondary.$key
                    }

                    $Primary.$key = Merge-Hashtables @splat
                }

                # if the key is an array merge the two items
                if ($primary.$key.GetType().Name -eq "Object[]" -and $secondary.$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 @($primary.$key, $secondary.$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
                    $primary.$key = $result
                }

                #force primary key, so remove secondary conflict
                $Secondary.Remove($key)

        }
    }

    #join the two hash tables and return to the calling function
    $Primary + $Secondary

}
Export-ModuleMember -Function Merge-Hashtables

Function ConvertTo-FlattenObject {
    # Version 00.02.12, by iRon
    [CmdletBinding()]Param (
        [Parameter(ValueFromPipeLine = $True)][Object[]]$Objects,
        [String]$Separator = ".", [ValidateSet("", 0, 1)]$Base = 1, [Int]$Depth = 5, [Int]$Uncut = 1,
        [String[]]$ToString = ([String], [DateTime], [TimeSpan]), [String[]]$Path = @()
    )
    $PipeLine = $Input | ForEach {$_}; If ($PipeLine) {$Objects = $PipeLine}
    If (@(Get-PSCallStack)[1].Command -eq $MyInvocation.MyCommand.Name -or @(Get-PSCallStack)[1].Command -eq "<position>") {
        $Object = @($Objects)[0]; $Iterate = New-Object System.Collections.Specialized.OrderedDictionary
        If ($ToString | Where-Object {$Object -is $_}) {$Object = $Object.ToString()}
        ElseIf ($Depth) {
            $Depth--
            If ($Object.GetEnumerator.OverloadDefinitions -match "[\W]IDictionaryEnumerator[\W]") {
                $Iterate = $Object
            }
            ElseIf ($Object.GetEnumerator.OverloadDefinitions -match "[\W]IEnumerator[\W]") {
                $Object.GetEnumerator() | ForEach-Object -Begin {$i = $Base} {$Iterate.($i) = $_; $i += 1}
            }
            Else {
                $Names = If ($Uncut) {$Uncut--} Else {$Object.PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames}
                If (!$Names) {$Names = $Object.PSObject.Properties | Where-Object {$_.IsGettable} | Select-Object -Expand Name}
                If ($Names) {$Names | ForEach-Object {$Iterate.$_ = $Object.$_}}
            }
        }
        If (@($Iterate.Keys).Count) {
            $Iterate.Keys | ForEach-Object {
                ConvertTo-FlattenObject @(, $Iterate.$_) $Separator $Base $Depth $Uncut $ToString ($Path + $_)
            }
        }
        Else {$Property.(($Path | Where-Object {$_}) -Join $Separator) = $Object}
    }
    ElseIf ($Objects -ne $Null) {
        @($Objects) | ForEach-Object -Begin {$Output = @(); $Names = @()} {
            New-Variable -Force -Option AllScope -Name Property -Value (New-Object System.Collections.Specialized.OrderedDictionary)
            ConvertTo-FlattenObject @(, $_) $Separator $Base $Depth $Uncut $ToString $Path
            $Output += New-Object PSObject -Property $Property
            $Names += $Output[-1].PSObject.Properties | Select -Expand Name
        }
        $Output | Select-Object ([String[]]($Names | Select-Object -Unique))
    }
};

Export-ModuleMember -Function ConvertTo-FlattenObject