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 |