internal/functions/Get-HydrationDefinitionSubfolderByContentId.ps1

<#
    .SYNOPSIS
        Retrieves the definition subfolder for a given content ID by searching through a policySetDefinition or policyAssignment. This is intended to be used in conjunction with Move-PolicyByAssignment as a parent script.
 
    .DESCRIPTION
        The Get-HydrationDefinitionSubfolderByContentId function retrieves the definition subfolder associated with a specific content ID.
        If found in a policySetDefinition, the function will check whether or not the assignment for that was located earlier in the parent script, which is defined in $CategoryList. If this assignment is found, then the assignment subfolder will be returned for that policySetDefinition's Assignment.
        If found in a policyAssignment, the function will return the subfolder of the assignment.
        If found in both, the higher security option will be taken.
        If found in neither, the function will return "NotFound" so that it can be placed in the designated location for unused definitions.
 
    .PARAMETER ContentId
        The ID of the policyAssignment or policy for which to retrieve the definition subfolder.
 
    .EXAMPLE
        Get-HydrationDefinitionSubfolderByContentId -ContentId "myPolicy" -ContainerDefinitionPath "C:\path\to\policyAssignments\myAssignment.json" -CategoryList $CategoryList
 
        This command retrieves the definition subfolder for the content with ID "12345".
 
    .LINK
        https://aka.ms/epac
        https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/Docs/start-hydration-kit.md
 
    #>

function Get-HydrationDefinitionSubfolderByContentId {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]
        $ContentId,
        [Parameter(Mandatory = $true)]
        [string]
        $ContainerDefinitionPath,
        [System.Management.Automation.OrderedHashtable]
        $CategoryList
    )
    if ($(Resolve-Path $ContainerDefinitionPath) -like "*policyAssignments*") {
        $intAssignmentPath = $ContainerDefinitionPath
        $fileType = "policyAssignments"
    }
    elseif ($(Resolve-Path $ContainerDefinitionPath) -like "*policySetDefinitions*") {
        $intPolicySetPath = $ContainerDefinitionPath
        $fileType = "policySetDefinitions"
    }
    Write-Debug $ContainerDefinitionPath
    Write-Debug " fileType: $fileType"
    if ($intAssignmentPath) {
        Write-Debug " Testing intAssignmentPath $intAssignmentPath for $ContentId..."
        $intAssignmentPath = Resolve-Path $intAssignmentPath
        $assignment = Get-Content -Path $intAssignmentPath | ConvertFrom-Json -Depth 100
        $relativePath = $intAssignmentPath -replace ".*policyAssignments[/\\]"
        Write-Debug " relativePath: $relativePath"
        Write-Debug " assignment.definitionEntryList: $($assignment.definitionEntryList)"
        Write-Debug " assignment.definitionEntry: $($assignment.definitionEntry)"
        if ($assignment.definitionEntryList) {
            Write-Debug " Testing $($assignment.definitionEntry.count) assigned definitions for $ContentId..."
            ForEach ($a in $assignment.definitionEntryList) {
                # policyId and policySetId are not necessary as they refer to built-in objects that are not managed within the stored hierarchy
                if ($a.policySetName -contains $ContentId -or $a.policyName -contains $ContentId) {
                    Write-Debug "Found $ContentId in $relativePath..."
                    $subfolder = ($relativePath -split '[/\\]')[0]
                    Write-Debug "Found $ContentId in $relativePath, will send to $subfolder..."
                    return $subfolder
                }
                else {
                    write-Debug "$ContentId not found in $intAssignmentPath"
                    return "NotFound"
                }
            }
        }
        elseif ($assignment.definitionEntry) {
            # policyId and policySetId are not necessary as they refer to built-in objects that are not managed within the stored hierarchy
            if ($assignment.definitionEntry.policySetName -eq $ContentId -or $assignment.definitionEntry.policyName -eq $ContentId) {
                Write-Debug "Found $ContentId in $relativePath..."
                $subfolder = ($relativePath -split '[/\\]')[0]
                return $subfolder
            }
            else {
                write-Debug "$ContentId not found in $intAssignmentPath"
                return "NotFound"
            }
        }
        else {
            write-Debug "$ContentId not found in $intAssignmentPath"
            return "NotFound"
        }
    }
    if ($intPolicySetPath) {
        if (!($CategoryList)) {
            Write-Error "CategoryList is required to process policySetDefinitions to the same location as the parent."
            return
        }
        if ($policySet.properties.policyDefinitions) {
            Write-Debug " $($policySet.Name) policyDefinitions.count: $($policySet.properties.policyDefinitions.count)"
            if ($policySet.properties.policyDefinitions.policyDefinitionName -contains $ContentId) {
                Write-Debug " Found $ContentId in $intPolicySetPath, checking assignment..."
                
                # Search through CategoryList for policySetPath here
                # If not found, throw error, this should have been categorized already in Move-PolicyByAssignment as policySets are processed first.
                $policySetAssignment = ($CategoryList | Where-Object { $_.Value.SourceFile -eq $intPolicySetPath }).NewFilePath
                Write-Debug "policySetAssignment.AssignmentFile: $($policySetAssignment.AssignmentFile)"
                if ($DebugPreference -eq "Continue") { $policySetAssignment }
                if ($policySetAssignment) {
                    $subfolder = (($policySetAssignment.AssignmentFile -replace ".*policyAssignments[/\\]") -split '[/\\]')[0]
                    return $subfolder
                }
                else {
                    Write-Error "The referenced policySet is not in the categorized list, this should not happen."
                }
                return $subfolder
            }
        }
        else {
            return "NotFound"
        }
    }
}