Private/Logic/Get-CategoryHierarchy.ps1

# Copyright (c) 2026 Sandy Zeng. All rights reserved.
# Source-available. All rights reserved. See LICENSE file.

<#
    Get-CategoryHierarchy.ps1 — Builds full category hierarchy paths from the configurationCategories.json data.
 
    Author: Sandy Zeng
    Project: IntuneDiff
 
    Version History:
    1.0.0 Initial release.
#>


function Initialize-CategoryData {
    <#
    .SYNOPSIS
        Loads configurationCategories.json once per session into $script:CategoriesData.
    #>

    [CmdletBinding()]
    param()

    if ($script:CategoriesData) { return }

    $path = Join-Path -Path $PSScriptRoot -ChildPath '..\..\Data\configurationCategories.json'
    if (-not (Test-Path -LiteralPath $path)) {
        $script:CategoriesData = @{}
        return
    }

    try {
        $json = Get-Content -LiteralPath $path -Raw -Encoding UTF8 | ConvertFrom-Json
    } catch {
        $script:CategoriesData = @{}
        return
    }

    $map = @{}
    foreach ($cat in @($json.value)) {
        if ($cat.id) {
            $map[[string]$cat.id] = [pscustomobject]@{
                Id               = [string]$cat.id
                DisplayName      = [string]$cat.displayName
                ParentCategoryId = [string]$cat.parentCategoryId
                RootCategoryId   = [string]$cat.rootCategoryId
            }
        }
    }
    $script:CategoriesData = $map
}

function Get-CategoryHierarchy {
    <#
    .SYNOPSIS
        Builds the full category hierarchy path for a category id (Root > Parent > Child).
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param([string]$CategoryId)

    if (-not $CategoryId) { return '' }
    Initialize-CategoryData
    if (-not $script:CategoriesData.ContainsKey($CategoryId)) { return '' }

    $parts = New-Object System.Collections.Generic.List[string]
    $visited = @{}
    $current = $CategoryId

    while ($current -and $script:CategoriesData.ContainsKey($current) -and -not $visited.ContainsKey($current)) {
        $visited[$current] = $true
        $cat = $script:CategoriesData[$current]
        if ($cat.DisplayName) { $parts.Insert(0, $cat.DisplayName) }

        $parentId = $cat.ParentCategoryId
        if (-not $parentId -or
            $parentId -eq '00000000-0000-0000-0000-000000000000' -or
            $parentId -eq $current) {
            break
        }
        $current = $parentId
    }

    return ($parts -join ' > ')
}

function Format-SettingNameWithCategory {
    <#
    .SYNOPSIS
        Returns a fully-qualified setting display name including special-case
        parent paths (LAPS, Firewall profiles) and the resolved category hierarchy.
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param(
        [string]$SettingName,
        [string]$CategoryId,
        [string]$SettingDefId
    )

    if ($SettingDefId) {
        $idLower = $SettingDefId.ToLowerInvariant()

        # LAPS
        if ($idLower.Contains('vendor_msft_laps_policies')) {
            if ($idLower -eq 'device_vendor_msft_laps_policies_backupdirectory') {
                return "LAPS > $SettingName"
            }
            return "LAPS > Backup Directory > $SettingName"
        }

        # Firewall - Domain profile
        if ($idLower.Contains('vendor_msft_firewall_mdmstore_domainprofile')) {
            if ($SettingName -like '*Enable Domain Network Firewall*') {
                return "Firewall > $SettingName"
            }
            return "Firewall > Enable Domain Network Firewall > $SettingName"
        }

        # Firewall - Private profile
        if ($idLower.Contains('vendor_msft_firewall_mdmstore_privateprofile')) {
            if ($SettingName -like '*Enable Private Network Firewall*') {
                return "Firewall > $SettingName"
            }
            return "Firewall > Enable Private Network Firewall > $SettingName"
        }

        # Firewall - Public profile
        if ($idLower.Contains('vendor_msft_firewall_mdmstore_publicprofile')) {
            if ($SettingName -like '*Enable Public Network Firewall*') {
                return "Firewall > $SettingName"
            }
            return "Firewall > Enable Public Network Firewall > $SettingName"
        }
    }

    if (-not $CategoryId) { return $SettingName }

    $hierarchy = Get-CategoryHierarchy -CategoryId $CategoryId
    if (-not $hierarchy) { return $SettingName }

    return "$hierarchy > $SettingName"
}