functions/New-HydrationCaf3Hierarchy.ps1


<#
.SYNOPSIS
    This function creates a new hierarchy of management groups based on the CAF 3.0 model.
 
.DESCRIPTION
    The New-HydrationCaf3Hierarchy function takes a prefix and a suffix, and creates a new hierarchy of management groups based on the CAF 3.0 model.
 
.PARAMETER Prefix
    The prefix to be used in the naming of the new hierarchy. This is not generally recommended as it adds complexity with little RoI, but is an available option.
 
.PARAMETER Suffix
    The suffix to be used in the naming of the new hierarchy. This is not generally recommended as it adds complexity with little RoI, but is an available option.
 
.EXAMPLE
    New-HydrationCaf3Hierarchy -Prefix "epacdev-" -Suffix "-dev"
 
    This will create a new hierarchy of management groups based on the CAF 3.0 model, using "epacdev-" as the prefix and "-dev" as the suffix.
 
.LINK
    https://aka.ms/epac
    https://github.com/Azure/enterprise-azure-policy-as-code/tree/main/Docs/start-hydration-kit.md
     
#>

function New-HydrationCaf3Hierarchy {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, HelpMessage = "The name of the destination root management group. This parameter is mandatory.")]
        [string]
        $DestinationRootName,
        [Parameter(Mandatory = $false, HelpMessage = "The prefix to be used in the naming of the new hierarchy. This is not generally recommended as it adds complexity with little RoI, but is an available option.")]
        [string]
        $Prefix,
        [Parameter(Mandatory = $false, HelpMessage = "The suffix to be used in the naming of the new hierarchy. This is not generally recommended as it adds complexity with little RoI, but is an available option.")]
        [string]
        $Suffix
    )
    $InformationPreference = "Continue"
    $mgLists = [ordered]@{
        $DestinationRootName = @("Platform", "LandingZones", "Decommissioned", "Sandbox")
        Platform             = @("Identity", "Management", "Connectivity")
        LandingZones         = @("Corp", "Online")
    }
    foreach ($listName in $mgLists.Keys) {
        if ($DestinationRootName -eq $listName) {
            $parentName = $listName
        }
        else {
            $parentName = $( -join ($Prefix, $listName, $Suffix))
        }
        $rootGroupId = $( -join ("/providers/Microsoft.Management/managementGroups/", $parentName))
        foreach ($t in $mgLists.($listName)) {
            $i = 0
            $name = $( -join ($Prefix, $t, $Suffix))
            Remove-Variable repeat -ErrorAction SilentlyContinue
            do {
                $null = Remove-variable testResult -ErrorAction SilentlyContinue
                $null = Remove-variable complete -ErrorAction SilentlyContinue
                try {
                    $null = $testResult = Get-AzManagementGroupRestMethod -GroupId $name -ErrorAction SilentlyContinue
                }
                catch {
                    $complete = $false
                }
                if ($testResult.name) {
                    # This exists for several reasons:
                    # First, timeout errors on response to new-azmanagementgroup are addressed this way.
                    # Second, this avoids collisions, and notifies of the location if one occurs.
                    # Third, this accelerates a retry if the first attempt is interrupted.
                    $complete = $true
                    Write-Information "Management Group $name confirmed in $($testResult.properties.details.parent.name)."
                }
                if (!($complete -eq $true)) {
                    try {
                        $null = $newMg = New-AzManagementGroup -GroupName $name -DisplayName $name -ParentId $rootGroupId -ErrorAction SilentlyContinue
                    }
                    catch {
                        $null = $newMg = Get-AzManagementGroupRestMethod -GroupId $name -ErrorAction SilentlyContinue
                        Write-Error $_.Exception.Message
                    }
                }
                if (!($newMg)) {
                    if ($i -gt 0) {
                        Write-Warning "Failed to Create Management Group $name, this is generally caused by a timeout on the API call, and will automatically retry $(10-$i) more times..."
                    }                    
                    $i++
                }
            }until($newMg -or $complete -or $i -eq 10)
            if ($i -eq 3) {
                Write-Error "Failed to create $name Management Group"
                return
            }
            Write-Information "Verified $name Management Group in $rootGroupId"
        }
    }
}