scripts/private/InitializeResourceTemplate.ps1

function InitializeResourceTemplate {
    [CmdletBinding()]
    [OutputType([void])]

    Param (
        [Parameter(Position = 0)]
        [System.Collections.Generic.List[AzBuilderScope]] $AzBuilderScope,

        [Parameter(Mandatory, Position = 1)]
        [string] $Path
    )

    try {
        [string[]] $ManagementGroups = $AzBuilderScope | Where-Object -Property 'Scope' -eq 'ManagementGroup' | Select-Object -ExpandProperty 'Name' -Unique
        [string[]] $Subscriptions = $AzBuilderScope | Where-Object -Property 'Scope' -eq 'Subscription' | Select-Object -ExpandProperty 'Name' -Unique
        [string] $TenantTemplateFilePath = '{0}\AzBuilder.Deploy.TenantResources_{1}.json' -f $Path, ((New-Guid).Guid.Substring(0,8))

        [pscustomobject] $TenantTemplateObject = @'
            {
                "$schema": "https://schema.management.azure.com/schemas/2019-08-01/tenantDeploymentTemplate.json#",
                "contentVersion": "1.0.0.0",
                "resources": [],
                "outputs": {
                    "deployments": {
                        "type": "array",
                        "value": []
                    }
                }
            }
'@
 | ConvertFrom-Json

        [System.Collections.Generic.List[pscustomobject]] $TenantResourcesToDeploy = @()
        [System.Collections.Generic.List[string]] $Deployments = @()

        foreach ($Item in ($AzBuilderScope | Where-Object -Property 'Scope' -eq 'Tenant')) {
            if ($Item.Templates) {
                [string] $TenantId = $Item.Parent.Split('/')[-1]

                foreach ($TemplateSet in $Item.Templates) {
                    [pscustomobject] $ResourceObject = @'
                        {
                            "type": "Microsoft.Resources/deployments",
                            "apiVersion": "2020-06-01",
                            "name": "",
                            "scope": "",
                            "location": "westeurope",
                            "properties": {
                                "mode": "Incremental",
                                "expressionEvaluationOptions": {
                                    "scope": "Inner"
                                },
                                "parameters": {},
                                "template": {}
                            },
                            "dependsOn": []
                        }
'@
 | ConvertFrom-Json

                    $ResourceObject.name = 'AzBuilder.{0}' -f (Split-Path -Path $TemplateSet.TemplateFilePath -LeafBase)
                    $ResourceObject.scope = 'Microsoft.Management/managementGroups/{0}' -f $TenantId
                    $ResourceObject.properties.template = Get-Content -Path $TemplateSet.TemplateFilePath | ConvertFrom-Json
                    $ResourceObject.properties.template.'$schema' = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
                    $Deployments.Add(('[reference(resourceId(''Microsoft.Resources/deployments'', ''{0}'')).outputs.deploymentName.value]' -f $ResourceObject.name))

                    if ($ResourceObject.properties.template.outputs) {
                        $ResourceObject.properties.template = $ResourceObject.properties.template | Select-Object -ExcludeProperty 'outputs'
                    }

                    $ResourceObject.properties.template | Add-Member -MemberType 'NoteProperty' -Name 'outputs' -Value @{
                        deploymentName = @{
                            type = 'string'
                            value = ''
                        }
                    }
                    $ResourceObject.properties.template.outputs.deploymentName.value = $ResourceObject.name

                    if ('{0}' -f $ResourceObject.properties.template.parameters) {
                        $ResourceObject.properties.template.parameters = [pscustomobject] @{
                            input = [pscustomobject] @{
                                type = 'object'
                            }
                        }

                        [pscustomobject] $ParameterObject = Get-Content -Path $TemplateSet.TemplateParametersFilePath | ConvertFrom-Json

                        if (-not $ParameterObject.parameters.input) {
                            $ParameterObject.parameters | Add-Member -MemberType 'NoteProperty' -Name 'input' -Value @{}
                        }

                        [string[]] $ParametersToConvert = ($ParameterObject.parameters | Get-Member -MemberType 'NoteProperty').Name

                        if ($ParametersToConvert -ne 'input') {
                            [pscustomobject] $InputObject = [pscustomobject] @{
                                input = [pscustomobject] @{
                                    value = [pscustomobject] @{}
                                }
                            }

                            foreach ($Parameter in $ParametersToConvert) {
                                if (-not ($Parameter -eq 'input')) {
                                    $InputObject.input.value | Add-Member -MemberType 'NoteProperty' -Name $Parameter -Value $ParameterObject.parameters.$Parameter.value
                                }
                            }

                            $ParameterObject.parameters = $InputObject
                        }

                        $ResourceObject.properties.parameters = $ParameterObject.parameters
                    }

                    if ($ResourceObject.properties.template.resources[0].dependsOn) {
                        [System.Collections.Generic.List[string]] $Dependencies = @()
                        foreach ($Dependency in $ResourceObject.properties.template.resources[0].dependsOn) {
                            $Dependencies.Add(('[resourceId(''Microsoft.Resources/deployments'', ''AzBuilder.{0}'')]' -f $Dependency))
                        }

                        $ResourceObject.dependsOn = [string[]] $Dependencies

                        $ResourceObject.properties.template.resources[0].dependsOn = @()
                    }

                    $TenantResourcesToDeploy.Add($ResourceObject)
                }

                $TenantTemplateObject.resources = [pscustomobject[]] $TenantResourcesToDeploy
                $TenantTemplateObject.outputs.deployments.value = [string[]] $Deployments

                if ($TenantTemplateObject.resources) {
                    $Template = $TenantTemplateObject | ConvertTo-Json -Depth 30

                    FormatTemplate $Template | Out-File $TenantTemplateFilePath
                }
            }
        }

        foreach ($ManagementGroupId in $ManagementGroups) {
            [string] $ManagementGroupPath = '{0}\managementgroups\{1}' -f $Path, $ManagementGroupId
            [string] $ManagementGroupTemplateFilePath = '{0}\AzBuilder.Deploy.ManagementGroupResources_{1}.json' -f $ManagementGroupPath, ((New-Guid).Guid.Substring(0,8))

            if (-not (Test-Path -Path $ManagementGroupPath)) {
                $null = New-Item -Path $ManagementGroupPath -ItemType 'Directory'
            }

            [pscustomobject] $ManagementGroupTemplateObject = @'
                {
                    "$schema": "https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#",
                    "contentVersion": "1.0.0.0",
                    "resources": [],
                    "outputs": {
                        "deployments": {
                            "type": "array",
                            "value": []
                        }
                    }
                }
'@
 | ConvertFrom-Json

            [System.Collections.Generic.List[pscustomobject]] $ManagementGroupResourcesToDeploy = @()
            [System.Collections.Generic.List[string]] $Deployments = @()

            foreach ($Item in ($AzBuilderScope | Where-Object -FilterScript {$_.Scope -eq 'ManagementGroup' -and $_.Name -eq $ManagementGroupId})) {
                if ($Item.Templates) {
                    foreach ($TemplateSet in $Item.Templates) {
                        [pscustomobject] $ResourceObject = @'
                            {
                                "type": "Microsoft.Resources/deployments",
                                "apiVersion": "2020-06-01",
                                "name": "",
                                "scope": "",
                                "location": "westeurope",
                                "properties": {
                                    "mode": "Incremental",
                                    "expressionEvaluationOptions": {
                                        "scope": "Inner"
                                    },
                                    "parameters": {},
                                    "template": {}
                                },
                                "dependsOn": []
                            }
'@
 | ConvertFrom-Json

                        $ResourceObject.name = 'AzBuilder.{0}' -f (Split-Path -Path $TemplateSet.TemplateFilePath -LeafBase)
                        $ResourceObject.scope = 'Microsoft.Management/managementGroups/{0}' -f $ManagementGroupId
                        $ResourceObject.properties.template = Get-Content -Path $TemplateSet.TemplateFilePath | ConvertFrom-Json
                        $ResourceObject.properties.template.'$schema' = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
                        $Deployments.Add(('[reference(resourceId(''Microsoft.Resources/deployments'', ''{0}'')).outputs.deploymentName.value]' -f $ResourceObject.name))

                        if ($ResourceObject.properties.template.outputs) {
                            $ResourceObject.properties.template = $ResourceObject.properties.template | Select-Object -ExcludeProperty 'outputs'
                        }

                        $ResourceObject.properties.template | Add-Member -MemberType 'NoteProperty' -Name 'outputs' -Value @{
                            deploymentName = @{
                                type = 'string'
                                value = ''
                            }
                        }
                        $ResourceObject.properties.template.outputs.deploymentName.value = $ResourceObject.name

                        if ('{0}' -f $ResourceObject.properties.template.parameters) {
                            $ResourceObject.properties.template.parameters = [pscustomobject] @{
                                input = [pscustomobject] @{
                                    type = 'object'
                                }
                            }

                            [pscustomobject] $ParameterObject = Get-Content -Path $TemplateSet.TemplateParametersFilePath | ConvertFrom-Json

                            if (-not $ParameterObject.parameters.input) {
                                $ParameterObject.parameters | Add-Member -MemberType 'NoteProperty' -Name 'input' -Value @{}
                            }

                            [string[]] $ParametersToConvert = ($ParameterObject.parameters | Get-Member -MemberType 'NoteProperty').Name

                            if ($ParametersToConvert -ne 'input') {
                                [pscustomobject] $InputObject = [pscustomobject] @{
                                    input = [pscustomobject] @{
                                        value = [pscustomobject] @{}
                                    }
                                }

                                foreach ($Parameter in $ParametersToConvert) {
                                    if (-not ($Parameter -eq 'input')) {
                                        $InputObject.input.value | Add-Member -MemberType 'NoteProperty' -Name $Parameter -Value $ParameterObject.parameters.$Parameter.value
                                    }
                                }

                                $ParameterObject.parameters = $InputObject
                            }

                            $ResourceObject.properties.parameters = $ParameterObject.parameters
                        }

                        if ($ResourceObject.properties.template.resources[0].dependsOn) {
                            [System.Collections.Generic.List[string]] $Dependencies = @()
                            foreach ($Dependency in $ResourceObject.properties.template.resources[0].dependsOn) {
                                $Dependencies.Add(('[resourceId(''Microsoft.Resources/deployments'', ''AzBuilder.{0}'')]' -f $Dependency))
                            }

                            $ResourceObject.dependsOn = [string[]] $Dependencies

                            $ResourceObject.properties.template.resources[0].dependsOn = @()
                        }

                        $ManagementGroupResourcesToDeploy.Add($ResourceObject)
                    }

                    $ManagementGroupTemplateObject.resources = [pscustomobject[]] $ManagementGroupResourcesToDeploy
                    $ManagementGroupTemplateObject.outputs.deployments.value = [string[]] $Deployments

                    if ($ManagementGroupTemplateObject.resources) {
                        $Template = $ManagementGroupTemplateObject | ConvertTo-Json -Depth 30

                        FormatTemplate $Template | Out-File $ManagementGroupTemplateFilePath
                    }
                }
            }
        }

        foreach ($SubscriptionId in $Subscriptions) {
            [string] $SubscriptionPath = '{0}\subscriptions\{1}' -f $Path, $SubscriptionId
            [string] $SubscriptionTemplateFilePath = '{0}\AzBuilder.Deploy.SubscriptionResources_{1}.json' -f $SubscriptionPath, ((New-Guid).Guid.Substring(0,8))

            if (-not (Test-Path -Path $SubscriptionPath)) {
                $null = New-Item -Path $SubscriptionPath -ItemType 'Directory'
            }

            [pscustomobject] $SubscriptionTemplateObject = @'
                {
                    "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
                    "contentVersion": "1.0.0.0",
                    "resources": [],
                    "outputs": {
                        "deployments": {
                            "type": "array",
                            "value": []
                        }
                    }
                }
'@
 | ConvertFrom-Json

            [System.Collections.Generic.List[pscustomobject]] $SubscriptionResourcesToDeploy = @()
            [System.Collections.Generic.List[string]] $Deployments = @()

            foreach ($Item in ($AzBuilderScope | Where-Object -FilterScript {$_.Scope -eq 'Subscription' -and $_.Name -eq $SubscriptionId})) {
                if ($Item.Templates) {
                    foreach ($TemplateSet in $Item.Templates) {
                        [pscustomobject] $ResourceObject = @'
                            {
                                "type": "Microsoft.Resources/deployments",
                                "apiVersion": "2020-06-01",
                                "name": "",
                                "subscriptionId": "",
                                "location": "westeurope",
                                "properties": {
                                    "mode": "Incremental",
                                    "expressionEvaluationOptions": {
                                        "scope": "Inner"
                                    },
                                    "parameters": {},
                                    "template": {}
                                },
                                "dependsOn": []
                            }
'@
 | ConvertFrom-Json

                        $ResourceObject.name = 'AzBuilder.{0}' -f (Split-Path -Path $TemplateSet.TemplateFilePath -LeafBase)
                        $ResourceObject.subscriptionId = $SubscriptionId
                        $ResourceObject.properties.template = Get-Content -Path $TemplateSet.TemplateFilePath | ConvertFrom-Json
                        $ResourceObject.properties.template.'$schema' = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
                        $Deployments.Add(('[reference(resourceId(''Microsoft.Resources/deployments'', ''{0}'')).outputs.deploymentName.value]' -f $ResourceObject.name))

                        if ($ResourceObject.properties.template.outputs) {
                            $ResourceObject.properties.template = $ResourceObject.properties.template | Select-Object -ExcludeProperty 'outputs'
                        }

                        $ResourceObject.properties.template | Add-Member -MemberType 'NoteProperty' -Name 'outputs' -Value @{
                            deploymentName = @{
                                type = 'string'
                                value = ''
                            }
                        }
                        $ResourceObject.properties.template.outputs.deploymentName.value = $ResourceObject.name

                        if ('{0}' -f $ResourceObject.properties.template.parameters) {
                            $ResourceObject.properties.template.parameters = [pscustomobject] @{
                                input = [pscustomobject] @{
                                    type = 'object'
                                }
                            }

                            [pscustomobject] $ParameterObject = Get-Content -Path $TemplateSet.TemplateParametersFilePath | ConvertFrom-Json

                            if (-not $ParameterObject.parameters.input) {
                                $ParameterObject.parameters | Add-Member -MemberType 'NoteProperty' -Name 'input' -Value @{}
                            }

                            [string[]] $ParametersToConvert = ($ParameterObject.parameters | Get-Member -MemberType 'NoteProperty').Name

                            if ($ParametersToConvert -ne 'input') {
                                [pscustomobject] $InputObject = [pscustomobject] @{
                                    input = [pscustomobject] @{
                                        value = [pscustomobject] @{}
                                    }
                                }

                                foreach ($Parameter in $ParametersToConvert) {
                                    if (-not ($Parameter -eq 'input')) {
                                        $InputObject.input.value | Add-Member -MemberType 'NoteProperty' -Name $Parameter -Value $ParameterObject.parameters.$Parameter.value
                                    }
                                }

                                $ParameterObject.parameters = $InputObject
                            }

                            $ResourceObject.properties.parameters = $ParameterObject.parameters
                        }

                        if ($ResourceObject.properties.template.resources[0].dependsOn) {
                            [System.Generic.Collections.List[string]] $Dependencies = @()
                            foreach ($Dependency in $ResourceObject.properties.template.resources[0].dependsOn) {
                                $Dependencies.Add(('[resourceId(''Microsoft.Resources/deployments'', ''AzBuilder.{0}'')]' -f $Dependency))
                            }

                            $ResourceObject.dependsOn = [string[]] $Dependencies

                            $ResourceObject.properties.template.resources[0].dependsOn = @()
                        }

                        $SubscriptionResourcesToDeploy.Add($ResourceObject)
                    }

                    $SubscriptionTemplateObject.resources = [pscustomobject[]] $SubscriptionResourcesToDeploy
                    $SubscriptionTemplateObject.outputs.deployments.value = [string[]] $Deployments

                    if ($SubscriptionTemplateObject.resources) {
                        $Template = $SubscriptionTemplateObject | ConvertTo-Json -Depth 30

                        FormatTemplate $Template | Out-File $SubscriptionTemplateFilePath
                    }
                }
            }

            foreach ($Item in ($AzBuilderScope | Where-Object -FilterScript {$_.Scope -eq 'ResourceGroup' -and $_.Parent -eq $SubscriptionId})) {
                [string] $ResourceGroupPath = '{0}\subscriptions\{1}\{2}' -f $Path, $SubscriptionId, $Item.Name
                [string] $ResourceGroupTemplateFilePath = '{0}\AzBuilder.Deploy.ResourceGroupResources_{1}.json' -f $ResourceGroupPath, ((New-Guid).Guid.Substring(0,8))

                if (-not (Test-Path -Path $ResourceGroupPath)) {
                    $null = New-Item -Path $ResourceGroupPath -ItemType 'Directory'
                }

                [pscustomobject] $ResourceGroupTemplateObject = @'
                    {
                        "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
                        "contentVersion": "1.0.0.0",
                        "resources": [],
                        "outputs": {
                            "deployments": {
                                "type": "array",
                                "value": []
                            }
                        }
                    }
'@
 | ConvertFrom-Json

                [System.Collections.Generic.List[pscustomobject]] $ResourceGroupResourcesToDeploy = @()
                [System.Collections.Generic.List[string]] $Deployments = @()

                if ($Item.Templates) {
                    foreach ($TemplateSet in $Item.Templates) {
                        [pscustomobject] $ResourceObject = @'
                            {
                                "type": "Microsoft.Resources/deployments",
                                "apiVersion": "2020-06-01",
                                "name": "",
                                "resourceGroup": "",
                                "properties": {
                                    "mode": "Incremental",
                                    "expressionEvaluationOptions": {
                                        "scope": "Inner"
                                    },
                                    "parameters": {},
                                    "template": {}
                                }
                            }
'@
 | ConvertFrom-Json

                        $ResourceObject.name = 'AzBuilder.{0}' -f (Split-Path -Path $TemplateSet.TemplateFilePath -LeafBase)
                        $ResourceObject.resourceGroup = $Item.Name
                        $ResourceObject.properties.template = Get-Content -Path $TemplateSet.TemplateFilePath | ConvertFrom-Json
                        $ResourceObject.properties.template.'$schema' = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
                        $Deployments.Add(('[reference(resourceId(''Microsoft.Resources/deployments'', ''{0}'')).outputs.deploymentName.value]' -f $ResourceObject.name))

                        if ($ResourceObject.properties.template.outputs) {
                            $ResourceObject.properties.template = $ResourceObject.properties.template | Select-Object -ExcludeProperty 'outputs'
                        }

                        $ResourceObject.properties.template | Add-Member -MemberType 'NoteProperty' -Name 'outputs' -Value @{
                            deploymentName = @{
                                type = 'string'
                                value = ''
                            }
                        }
                        $ResourceObject.properties.template.outputs.deploymentName.value = $ResourceObject.name

                        if ('{0}' -f $ResourceObject.properties.template.parameters) {
                            $ResourceObject.properties.template.parameters = [pscustomobject] @{
                                input = [pscustomobject] @{
                                    type = 'object'
                                }
                            }

                            [pscustomobject] $ParameterObject = Get-Content -Path $TemplateSet.TemplateParametersFilePath | ConvertFrom-Json

                            if (-not $ParameterObject.parameters.input) {
                                $ParameterObject.parameters | Add-Member -MemberType 'NoteProperty' -Name 'input' -Value @{}
                            }

                            [string[]] $ParametersToConvert = ($ParameterObject.parameters | Get-Member -MemberType 'NoteProperty').Name

                            if ($ParametersToConvert -ne 'input') {
                                [pscustomobject] $InputObject = [pscustomobject] @{
                                    input = [pscustomobject] @{
                                        value = [pscustomobject] @{}
                                    }
                                }

                                foreach ($Parameter in $ParametersToConvert) {
                                    if (-not ($Parameter -eq 'input')) {
                                        $InputObject.input.value | Add-Member -MemberType 'NoteProperty' -Name $Parameter -Value $ParameterObject.parameters.$Parameter.value
                                    }
                                }

                                $ParameterObject.parameters = $InputObject
                            }

                            $ResourceObject.properties.parameters = $ParameterObject.parameters
                        }

                        if ($ResourceObject.properties.template.resources[0].dependsOn) {
                            [System.Generic.Collections.List[string]] $Dependencies = @()
                            foreach ($Dependency in $ResourceObject.properties.template.resources[0].dependsOn) {
                                $Dependencies.Add(('[resourceId(''Microsoft.Resources/deployments'', ''AzBuilder.{0}'')]' -f $Dependency))
                            }

                            $ResourceObject.dependsOn = [string[]] $Dependencies

                            $ResourceObject.properties.template.resources[0].dependsOn = @()
                        }

                        $ResourceGroupResourcesToDeploy.Add($ResourceObject)
                    }

                    $ResourceGroupTemplateObject.resources = [pscustomobject[]] $ResourceGroupResourcesToDeploy
                    $ResourceGroupTemplateObject.outputs.deployments.value = [string[]] $Deployments

                    if ($ResourceGroupTemplateObject.resources) {
                        $Template = $ResourceGroupTemplateObject | ConvertTo-Json -Depth 30

                        FormatTemplate $Template | Out-File $ResourceGroupTemplateFilePath
                    }
                }
            }
        }
    } catch {
        $PSCmdlet.ThrowTerminatingError($PSItem)
    }
}