functions/Sync-ALZPolicyFromLibrary.ps1

function Sync-ALZPolicyFromLibrary {
Param(
   
    [Parameter(Mandatory = $false)]
    [string] $DefinitionsRootFolder,

    [ValidateSet("ALZ", "AMBA")]
    [string]$Type = "ALZ",
 
    [Parameter(Mandatory = $true)]
    [string]$PacEnvironmentSelector,

    [string]$LibraryPath
)

if ($LibraryPath -eq "") {
    if ($Tag) {
        git clone --depth 1 --branch $Tag https://github.com/anwather/Azure-Landing-Zones-Library.git .\temp
        $LibraryPath = ".\temp"
    }
    else {
        git clone --depth 1 https://github.com/anwather/Azure-Landing-Zones-Library.git .\temp
        $LibraryPath = ".\temp"
    }
}

if ($DefinitionsRootFolder -eq "") {
    if ($null -eq $env:PAC_DEFINITIONS_FOLDER) {
        if ($ModuleRoot) {
            $DefinitionsRootFolder = "./Definitions"
        }
        else {
            $DefinitionsRootFolder = "$PSScriptRoot/../../Definitions"
        }
    }
    else {
        $DefinitionsRootFolder = $env:PAC_DEFINITIONS_FOLDER
    }
}

try {
    $telemetryEnabled = (Get-Content $DefinitionsRootFolder/global-settings.jsonc | ConvertFrom-Json).telemetryOptOut
    $deploymentRootScope = (Get-Content $DefinitionsRootFolder/global-settings.jsonc | ConvertFrom-Json).pacEnvironments[0]
    if (!($telemetryEnabled)) {
        Write-Information "Telemetry is enabled"
        Submit-EPACTelemetry -Cuapid "pid-adaa7564-1962-46e6-92b4-735e91f76d43" -DeploymentRootScope $deploymentRootScope
    }
    else {
        Write-Information "Telemetry is disabled"
    }
}
catch {}

New-Item -Path "$DefinitionsRootFolder\policyDefinitions" -ItemType Directory -Force -ErrorAction SilentlyContinue
New-Item -Path "$DefinitionsRootFolder\policyDefinitions\$Type" -ItemType Directory -Force -ErrorAction SilentlyContinue
New-Item -Path "$DefinitionsRootFolder\policySetDefinitions" -ItemType Directory -Force -ErrorAction SilentlyContinue
New-Item -Path "$DefinitionsRootFolder\policySetDefinitions\$Type" -ItemType Directory -Force -ErrorAction SilentlyContinue
New-Item -Path "$DefinitionsRootFolder\policyAssignments" -ItemType Directory -Force -ErrorAction SilentlyContinue
New-Item -Path "$DefinitionsRootFolder\policyAssignments\$Type" -ItemType Directory -Force -ErrorAction SilentlyContinue

# Create policy definition objects

foreach ($file in Get-ChildItem -Path "$LibraryPath\platform\$($Type.ToLower())\policy_definitions" -Recurse -File -Include *.json) {
    $fileContent = Get-Content -Path $file.FullName -Raw | ConvertFrom-Json
    $baseTemplate = @{
        name       = $fileContent.name
        properties = $fileContent.properties
    }
    $category = $baseTemplate.properties.Metadata.category
    if (!(Test-Path $DefinitionsRootFolder\policyDefinitions\$Type\$category)) {
        New-Item -Path $DefinitionsRootFolder\policyDefinitions\$Type\$category -ItemType Directory -Force -ErrorAction SilentlyContinue
    }
    $baseTemplate | Select-Object name, properties | ConvertTo-Json -Depth 50 | Out-File -FilePath $DefinitionsRootFolder\policyDefinitions\$Type\$category\$($fileContent.name).json -Force
    (Get-Content $DefinitionsRootFolder\policyDefinitions\$Type\$category\$($fileContent.name).json) -replace "\[\[", "[" | Set-Content $DefinitionsRootFolder\policyDefinitions\$Type\$category\$($fileContent.name).json
}

# Create policy set definition objects

foreach ($file in Get-ChildItem -Path "$LibraryPath\platform\$($Type.ToLower())\policy_set_definitions" -Recurse -File -Include *.json) {
    $fileContent = Get-Content -Path $file.FullName -Raw | ConvertFrom-Json
    $baseTemplate = @{
        name       = $fileContent.name
        properties = @{
            description            = $fileContent.properties.description
            displayName            = $fileContent.properties.displayName
            metadata               = $fileContent.properties.metadata
            parameters             = $fileContent.properties.parameters
            policyType             = $fileContent.properties.policyType
            policyDefinitionGroups = $fileContent.properties.policyDefinitionGroups
        }
    }
    $policyDefinitions = @()
    # Fix the policyDefinitionIds for custom policies
    foreach ($policyDefinition in $fileContent.properties.policyDefinitions) {
        $obj = @{
            parameters                  = $policyDefinition.parameters
            groupNames                  = $policyDefinition.groupNames
            policyDefinitionReferenceId = $policyDefinition.policyDefinitionReferenceId
        }
        if ($policyDefinition.policyDefinitionId -match "managementGroups") {
            $obj.Add("policyDefinitionName", $policyDefinition.policyDefinitionId.split("/")[-1])
        }
        else {
            $obj.Add("policyDefinitionId", $policyDefinition.policyDefinitionId)
        }
        $policyDefinitions += $obj
    }
    $baseTemplate.properties.policyDefinitions = $policyDefinitions

    $category = $baseTemplate.properties.Metadata.category
    if (!(Test-Path $DefinitionsRootFolder\policySetDefinitions\$Type\$category)) {
        New-Item -Path $DefinitionsRootFolder\policySetDefinitions\$Type\$category -ItemType Directory -Force -ErrorAction SilentlyContinue
    }
    $baseTemplate | Select-Object name, properties | ConvertTo-Json -Depth 50 | Out-File -FilePath $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json -Force
    (Get-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json) -replace "\[\[", "[" | Set-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json
    (Get-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json) -replace "variables\('scope'\)", "'/providers/Microsoft.Management/managementGroups/$managementGroupId'" | Set-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json
    (Get-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json) -replace "', '", "" | Set-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json
    (Get-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json) -replace "\[concat\(('(.+)')\)\]", "`$2" | Set-Content $DefinitionsRootFolder\policySetDefinitions\$Type\$category\$($fileContent.name).json
}

# Create assignment objects

try {
    $structureFile = Get-Content .\$Type.policy_default_structure.json -ErrorAction Stop | ConvertFrom-Json
    switch ($structureFile.enforcementMode) {
        "Default" { $enforcementModeText = "must" }
        "DoNotEnforce" { $enforcementModeText = "should" }
    }
}
catch {
    Write-Host "No policy default structure file found. Please run Create-ALZPolicyDefaultStructure.ps1 first."
    exit
}

foreach ($file in Get-ChildItem -Path "$LibraryPath\platform\$($Type.ToLower())\archetype_definitions" -Recurse -File -Include *.json) {
    $archetypeContent = Get-Content -Path $file.FullName -Raw | ConvertFrom-Json
    foreach ($requiredAssignment in $archetypeContent.policy_assignments) {
        switch ($Type) {
            "ALZ" { $fileContent = Get-ChildItem -Path $LibraryPath\platform\$Type\policy_assignments | Where-Object { $_.BaseName.Split(".")[0] -eq $requiredAssignment } | Get-Content -Raw | ConvertFrom-Json }
            "AMBA" { $fileContent = Get-ChildItem -Path $LibraryPath\platform\$Type\policy_assignments | Where-Object { $_.BaseName.Split(".")[0].Replace("_", "-") -eq $requiredAssignment } | Get-Content -Raw | ConvertFrom-Json }
            default { $fileContent = Get-ChildItem -Path $LibraryPath\platform\$Type\policy_assignments | Where-Object { $_.BaseName.Split(".")[0] -eq $requiredAssignment } | Get-Content -Raw | ConvertFrom-Json }
        }
        

        $baseTemplate = @{
            nodeName        = "$($archetypeContent.name)/$($fileContent.name)"
            assignment      = @{
                name        = $fileContent.Name
                displayName = $fileContent.properties.displayName
                description = $fileContent.properties.description
            }
            definitionEntry = @{
                displayName = $fileContent.properties.displayName
            }
            parameters      = @{}
            enforcementMode = $structureFile.enforcementMode
        }

        # Definition Version
        if ($null -ne $fileContent.properties.definitionVersion) {
            $baseTemplate.Add("definitionVersion", $fileContent.properties.definitionVersion)
        }
    
        # Definition Entry
        if ($fileContent.properties.policyDefinitionId -match "placeholder.+policySetDefinition") {
            $baseTemplate.definitionEntry.Add("policySetName", ($fileContent.properties.policyDefinitionId).Split("/")[-1])
        }
        elseif ($fileContent.properties.policyDefinitionId -match "placeholder.+policyDefinition") {
            $baseTemplate.definitionEntry.Add("policyName", ($fileContent.properties.policyDefinitionId).Split("/")[-1])
        }
        else {
            if ($fileContent.properties.policyDefinitionId -match "policySetDefinitions") {
                $baseTemplate.definitionEntry.Add("policySetId", ($fileContent.properties.policyDefinitionId))
            }
            else {
                $baseTemplate.definitionEntry.Add("policyId", ($fileContent.properties.policyDefinitionId))
            }
            
        }
    
        #Scope
        $scopeTrim = $file.BaseName.split(".")[0]
        if ($scopeTrim -eq "root") {
            $scopeTrim = "alz"
        }
        if ($scopeTrim -eq "landing_zones") {
            $scopeTrim = "landingzones"
        }
        $scope = @{
            $PacEnvironmentSelector = @(
                $structureFile.managementGroupNameMappings.$scopeTrim.value
            )
        }
        $baseTemplate.Add("scope", $scope)

        # Base Parameters
        if ($fileContent.name -ne "Deploy-Private-DNS-Zones") {
            foreach ($parameter in $fileContent.properties.parameters.psObject.Properties.Name) {
                $baseTemplate.parameters.Add($parameter, $fileContent.properties.parameters.$parameter.value)
            }
        }

        # Non-compliance messages
        if ($null -ne $fileContent.properties.nonComplianceMessages) {
            $obj = @(
                @{
                    message = $fileContent.properties.nonComplianceMessages.message -replace "{enforcementMode}", $enforcementModeText
                }
            )
            $baseTemplate.Add("nonComplianceMessages", $obj)
        }
    

        # Check for explicit parameters
        if ($fileContent.name -ne "Deploy-Private-DNS-Zones") {
            foreach ($key in $structureFile.defaultParameterValues.psObject.Properties.Name) {
                if ($structureFile.defaultParameterValues.$key.policy_assignment_name -eq $fileContent.name) {
                    $keyName = $structureFile.defaultParameterValues.$key.parameters.parameter_name
                    $baseTemplate.parameters.$keyName = $structureFile.defaultParameterValues.$key.parameters.value
                }
            }
        }
        else {
            $dnsZoneRegion = $structureFile.defaultParameterValues.private_dns_zone_region.parameters.value
            $dnzZoneSubscription = $structureFile.defaultParameterValues.private_dns_zone_subscription_id.parameters.value
            $dnzZoneResourceGroupName = $structureFile.defaultParameterValues.private_dns_zone_resource_group_name.parameters.value
            foreach ($parameter in $fileContent.properties.parameters.psObject.Properties.Name) {
                $value = "/subscriptions/$dnzZoneSubscription/resourceGroups/$dnzZoneResourceGroupName/providers/Microsoft.Network/privateDnsZones/$($fileContent.properties.parameters.$parameter.value.split("/")[-1])"
                #$value = $fileContent.properties.parameters.$parameter.value -replace "00000000-0000-0000-0000-000000000000", $dnzZoneSubscription -replace "placeholder", $dnzZoneResourceGroupName
                $baseTemplate.parameters.Add($parameter, $value)
            }
        }
        

        $category = $structureFile.managementGroupNameMappings.$scopeTrim.management_group_function
        if (!(Test-Path $DefinitionsRootFolder\policyAssignments\$Type\$category)) {
            New-Item -Path $DefinitionsRootFolder\policyAssignments\$Type\$category -ItemType Directory -Force -ErrorAction SilentlyContinue
        }
        $baseTemplate | Select-Object nodeName, assignment, definitionEntry, definitionVersion, enforcementMode, parameters, nonComplianceMessages, scope | ConvertTo-Json -Depth 50 | Out-File -FilePath $DefinitionsRootFolder\policyAssignments\$Type\$category\$($fileContent.name).json -Force
        (Get-Content $DefinitionsRootFolder\policyAssignments\$Type\$category\$($fileContent.name).json) -replace "\[\[", "[" | Set-Content $DefinitionsRootFolder\policyAssignments\$Type\$category\$($fileContent.name).json
        if ($fileContent.name -eq "Deploy-Private-DNS-Zones") {
            (Get-Content $DefinitionsRootFolder\policyAssignments\$Type\$category\$($fileContent.name).json) -replace "\.ne\.", ".$dnsZoneRegion." | Set-Content $DefinitionsRootFolder\policyAssignments\$Type\$category\$($fileContent.name).json
        }
    }
    

}

if ($LibraryPath -eq ".\temp") {
    Remove-Item .\temp -Recurse -Force -ErrorAction SilentlyContinue
}

}