Home How to track path/key during recursion through hash of hashes in PowerShell?
Reply: 0

How to track path/key during recursion through hash of hashes in PowerShell?

user11822
1#
user11822 Published in September 20, 2018, 10:22 pm

I've been trying to compare two hashes of hashes against each other. Unfortunately even with the great help from here I struggled to pull together what I was trying to do.

So, I've resorted to searching the internet again and I was lucky enough to find Edxi's code (full credit to him and Dbroeglin who looks to have written it originally)

https://gist.github.com/edxi/87cb8a550b43ec90e4a89d2e69324806

His compare-hash function does exactly what I needed in terms of its comparisons. However, I'd like to report of the full path of the hash in the final output. So I've tried to update the code to allow for this. My thinking being that I should be able to take the Key (aka path) while the code loops over itself but I'm clearly going about it in the wrong manner.

Am I going about this with the right approach, and if not, would someone suggest another method please? The biggest problem I've found so far is that if I change the hash, my code changes don't work e.g. adding 'More' = 'stuff' So it becomes $sailings.Arrivals.PDH083.More breaks the path in the way I've set it.

My version of the code:

$Sailings = @{
    'Arrivals'   = @{
        'PDH083' = @{
            'GoingTo'   = 'Port1'
            'Scheduled' = '09:05'
            'Expected'  = '10:11'
            'Status'    = 'Delayed'
        }
    }
    'Departures' = @{
        'PDH083' = @{
            'ArrivingFrom' = 'Port1'
            'Scheduled'    = '09:05'
            'Expected'     = '09:05'
            'Status'       = 'OnTime'
            'Other'        = @{'Data' = 'Test'}
        }
    }
}

$Flights = @{
    'Arrivals'   = @{
        'PDH083' = @{
            'GoingTo'   = 'Port'
            'Scheduled' = '09:05'
            'Expected'  = '10:20'
            'Status'    = 'Delayed'

        }
    }
    'Departures' = @{
        'PDH083' = @{
            'ArrivingFrom' = 'Port11'
            'Scheduled'    = '09:05'
            'Expected'     = '09:05'
            'Status'       = 'NotOnTime'
            'Other'        = @{'Data' = 'Test_Diff'}
        }
    }
}


function Compare-Hashtable {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [Hashtable]$Left,

        [Parameter(Mandatory = $true)]
        [Hashtable]$Right,
        [string] $path,
        [boolean] $trackpath = $True
    )
    write-host "PAth received as: $path"
    function New-Result($Key, $LValue, $Side, $RValue) {
        New-Object -Type PSObject -Property @{
            key    = $Key
            lvalue = $LValue
            rvalue = $RValue
            side   = $Side
        }
    }




    [Object[]]$Results = $Left.Keys | ForEach-Object {

        if ($trackpath ) {
            write-host "Working on Path: " $path + $_
        }

        if ($Left.ContainsKey($_) -and !$Right.ContainsKey($_)) {
            write-host "Right key not matched. Report path as: $path"
            New-Result $path $Left[$_] "<=" $Null
        }
        else {
            if ($Left[$_] -is [hashtable] -and $Right[$_] -is [hashtable] ) {
                if ($path -ne $null -or $path -ne "/") {
                    $path = $path + "/" + $_
                    write-host "Sending Path to function as: $path"
                }
                Compare-Hashtable $Left[$_] $Right[$_] $path
            }
            else {
                $LValue, $RValue = $Left[$_], $Right[$_]
                if ($LValue -ne $RValue) {
                    $path = $path + "/" + $_
                    write-host "Not a hash so must be a value at path:$path"
                    New-Result $path $LValue "!=" $RValue
                }
                else {
                    Write-Host "Before changing path: $path "
                    if (($path.Substring(0, $path.lastIndexOf('/'))).length >0) {
                        $path = $path.Substring(0, $path.lastIndexOf('/'))
                        Write-Host "After changing path: $path "
                    }
                }
            }

        }
       # if (($path.Substring(0, $path.lastIndexOf('/'))).length >0) { 
       # Tried to use this to stop error on substring being less than zero
       # but clearly doesnt work when you add more levels to the hash 
                   $path = $path.Substring(0, $path.lastIndexOf('/'))
       # } else { $path = $path.Substring(0, $path.lastIndexOf('/')) }

    }



    $Results += $Right.Keys | ForEach-Object {
        if (!$Left.ContainsKey($_) -and $Right.ContainsKey($_)) {
            New-Result $_ $Null "=>" $Right[$_]

        }
    }


    if ($Results -ne $null) { $Results }
}
cls

Compare-Hashtable $Sailings $Flights

outputs
key                             lvalue side rvalue
---                             ------ ---- ------
/Arrivals/PDH083/Expected       10:11  !=   10:20
/Arrivals/GoingTo               Port1  !=   Port
/Departures/PDH083/ArrivingFrom Port1  !=   Port11
/Departures/PDH083/Status       OnTime !=   NotOnTime
/Departures/PDH083/Other/Data   Test   !=   Test_Diff
share|improve this question
  • You can also see that my code looses the PDH083 key on the Arrivals/GoingTo output. So, clearly I am tackling this in the wrong manner. – Spacey Feb 13 at 11:35
  • Thanks @halfer for editing the question. Apologies, I'll reframe from posting unnecessary commentary in future. As for the standard of my English, well I tried my best, but I guess it’s a good as my coding abilities. – Spacey Feb 13 at 15:07
  • Your English seems excellent to me! :-) Yes, we like things succinct here. – halfer Feb 13 at 15:09

1 Answer 1

active oldest votes
up vote 0 down vote accepted
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.327909 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO