internal/functions/Test-HydrationCaf3Hierarchy.ps1

function Test-HydrationCaf3Hierarchy {
    <#
.SYNOPSIS
    Tests the hierarchy of Azure Management Groups for a specified tenant to see if a standard CAF 3.0 hierarchy is in place.
 
.DESCRIPTION
    This script retrieves the structure of Azure Management Groups for a specified tenant and verifies that the management groups have the correct parent-child relationships.
 
.PARAMETER TenantId
    The Tenant ID of the Azure Active Directory tenant. If not specified, the Tenant ID from the current Azure context will be used.
 
.EXAMPLE
    .\Test-HydrationCaf3Hierarchy -TenantId "your-tenant-id"
 
    This example runs the script for the specified Tenant ID.
 
.EXAMPLE
    .\Test-HydrationCaf3Hierarchy
 
    This example runs the script using the Tenant ID from the current Azure context.
 
.LINK
    https://aka.ms/epac
    https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/Docs/start-hydration-kit.md
     
#>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [string]
        $TenantId,
        [Parameter(Mandatory = $false)]
        [string]
        $TenantIntermediateRoot = "TenantIntermediateRoot",
        $LogFilePath,
        $Output = "./Output"
    )
    if (!($LogFilePath)) {
        $LogFilePath = Join-Path $Output "Logs" "HydrationTests.log"
    }
    $mgPairs = [ordered]@{
        LandingZones            = @("Corp", "Online")
        Platform                = @("Identity", "Management", "Connectivity")
        $TenantIntermediateRoot = @("Decomissioned", "Sandbox", "Platform", "LandingZones")
    }
    if ((!$TenantId) -or ($TenantId -eq "")) {
        $TenantId = (Get-AzContext).Tenant.Id
    }
    $mgPullIncrement = 0
    do {
        $mgPullIncrement++
        try {
            $mgStructure = Get-AzManagementGroupRestMethod -GroupId $TenantId -Expand -Recurse
        }
        catch {
            if ($mgPullIncrement -eq 3) {
                Write-Error "Failed to retrieve Management Group structure after 3 attempts, exiting. Reconnect to Azure and retry test."
            
            }
            Write-Warning "Failed to retrieve Management Group structure, retrying $(10-$mgPullIncrement) more times..."
        }
    }until($mgStructure -or $mgPullIncrement -eq 3)

    $testResults = @{}
    try {
        $tenantIntermediateRootResult = Get-AzManagementGroupRestMethod -GroupId $TenantIntermediateRoot -ErrorAction Stop
    }
    catch {
        if (($_.Exception.Message -like "*error 403*" -or $_.Exception.Message -like "*error 404*")) {
            $tenantIntermediateRootResult = "Available"  
        }
        else {
            Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "$_.Exception.Message"   -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Red
            Write-Error $_.Exception.Message
        }
    }
    foreach ($mgKey in $mgPairs.keys) {
        $currentList = $mgPairs.$mgKey
        $parentName = $mgKey
        foreach ($mg in $currentList) {
            try {
                $mgListing = Get-AzManagementGroupRestMethod -GroupId $mg -ErrorAction Stop
            }
            catch {
                if ($_.Exception.Message -like "*error 403*" -or $_.Exception.Message -like "*error 404*") {
                    $testResults.add($mg, "Available")
                    Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "$mg Available: Failed to retrieve management group $mg" -Silent  -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Yellow
                    continue
                }
                else {
                    Write-Error $_.Exception.Message
                    Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "$_.Exception.Message" -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Red
                    return "Failed"
                }
            }
            if ($mgListing.properties.details.parent.name -eq $parentName) {
                $testResults.add($mg, "ParentPassed")
                Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "$mg has standard CAF3 parent, $parentName" -Silent -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Green
            }
            else {
                Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "Standard CAF3 Naming Option Will Fail: Actual Parent `"$($mgListing.properties.details.parent.name)`" for management group `"$mg`" does not match expected parent `"$parentName`"..." -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Yellow
                return "FailedNameCollision"
            }
        }
    }
    if ($testResults.count -gt 1) {
        if ($testResults.Values -contains "ParentPassed" -and (!($testResults.Values -contains "Available"))) {
            Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "Passed: All Management Groups have the correct parent-child relationships in the CAF3 hierarchy under the management group `"$TenantIntermediateRoot`"."   -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Green
            return "PassedCaf3Exists"
        }
        elseif ($testResults.Values -contains "Available" -and (!($testResults.Values -contains "FailedNameCollision"))) {
            # Write-HydrationLogFile -EntryType logEntryDataAsPresented -EntryData "Passed: There are existing Management Groups with the same name, but they exist in the appropriate place in the CAF3 hierarchy under the management group `"$TenantIntermediateRoot`". However, the deployment remains incomplete." -LogFilePath $logFilePath -UseUtc:$UseUtc -ForegroundColor Green
            return "PassedRunCaf3"
            
        }
        else {
            $failString = $testResults | ConvertTo-Json -Depth 20
            return "Failed, report bug to EPAC team. Data: $failString"
        }
    }
    else {
        return "Failed, report bug to EPAC team. No evaluations returned for Test-HydrationCaf3Hierarchy...."
    }
}