Home > database >  How to reverse traverse a nested hashtable in PowerShell
How to reverse traverse a nested hashtable in PowerShell

Time:04-20

In a previous question, I was given a solution for finding the name of a key by its value. Unfortunately I neglected to consider the application of Security Groups

Old hashtable and working function

$Departments = @{
    'Sales' = @{
        'SAM' = 'Manager'
        'SAP' = 'Person'
    }
    'IT'    = @{
        'ITM' = 'Manager'
        'ITS' = 'Specialist'
        'ITT' = 'Technician'
        'ITC' = 'Consultant'     
    }
}

function Get-DepartmentOU {
    Param (
        [CmdletBinding()]
        [Parameter(Mandatory = $true)]
        [System.String]
        $RoleCode
    )

    # Get the DictionaryEntry in the main Hashtable where the nested Hashtable value matches the role you are looking for.
    $Department = $script:Departments.GetEnumerator() | Where-Object { $_.Value.ContainsKey($RoleCode) }

    # Print the name of the DictionaryEntry (Your department) and retrieve the value from the Hashtable for the role.
    "Department: $($Department.Name) Job Title: $($Department.Value[$RoleCode])" 

}


$JobCode = "SAM"
$DepartmentInfo = Get-DepartmentOU -RoleCode $JobCode
$DepartmentInfo

OUTPUT: Department: Sales Job Title: Manager

The above works excellently, however I've now created a deeper hashtable and need to do the same thing, just another level to extract more information.

New hashtable

$Departments = @{
    "Parts" = @{
        "SG-Parts" = @{
            "PAM" = "Parts Manager"
            "PAA" = "Parts Advisor"
        }
    }
    "Sales" = @{
        "SG-Sales"          = @{
            "SAP" = "Sales Person"
            "SAR" = "Receptionist"
        }
        "SG-Sales Managers" = @{
            "SGM" = "General Manager"
            "SAM" = "Sales Manager"
        }

    }
}

How should I change the working function to display the text contained in the key

OUTPUT: SG: SG-Sales Managers Department: Sales Job Title: Manager

CodePudding user response:

Create a new flat role table from your OU-like hashtable structure:

$RoleMap = @{}

foreach($departmentCode in $Departments.psbase.Keys){
    foreach($sgCode in $Departments[$departmentCode].psbase.Keys){
        foreach($roleCode in $Departments[$departmentCode][$sgCode].psbase.Keys){
            # Create a summary object that includes all 3 pieces of information
            # Store in role table and use the "role code" as the key
            $RoleMap[$roleCode] = [pscustomobject]@{
                Title = $Departments[$departmentCode][$sgCode][$roleCode]
                SG = $sgCode
                Department = $departmentCode
            }
        }
    }
}

Now you can avoid ...GetEnumerator() | Where-Object { ... } completely when resolving the role code:

function Get-DepartmentOU {
    param(
        [CmdletBinding()]
        [Parameter(Mandatory = $true)]
        [string]
        $RoleCode
    )

    if($script:RoleMap.Contains($RoleCode)){
        # `Where-Object` no longer needed!
        $roleDescription = $script:RoleMap[$RoleCode]

        "SG: $($roleDescription.SG) Department: $($roleDescription.Name) Job Title: $($roleDescription.Title)"
    }
}
  • Related