scripts/private/GetResources.ps1

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

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

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

        [Parameter(Position = 2)]
        [string] $TemporaryPath = '{0}\azbuilder-blueprints' -f $env:TEMP
    )

    try {
        [regex] $GuidRegex = [regex]::new('(?i)[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}')
        [Microsoft.Azure.Commands.Profile.Models.PSAzureSubscription[]] $Subscriptions = Get-AzSubscription | Where-Object -Property 'State' -eq 'Enabled'

        foreach ($Subscription in $Subscriptions) {
            $null = Set-AzContext -SubscriptionObject $Subscription

            [Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.Policy.PsPolicyDefinition[]] $PolicyDefinitions = Get-AzPolicyDefinition -Custom

            foreach ($PolicyDefinition in $PolicyDefinitions) {
                if (-not ($PolicyDefinition.ResourceId.Split('/')[1] -eq 'subscriptions')) {
                    [string] $PolicyDefinitionScope = $PolicyDefinition.ResourceId.Split('/')[4]

                    if ($PolicyDefinitionScope -match $GuidRegex) {
                        [string] $PolicyDefinitionScope = 'Tenant'
                    }
                } else {
                    [string] $PolicyDefinitionScope = $PolicyDefinition.ResourceId.Split('/')[2]
                }

                [string[]] $ResourceType = $PolicyDefinition.ResourceType.Split('/')
                [string] $ResourceFileName = '{0}_{1}-{2}.json' -f $ResourceType[0], $ResourceType[1], $PolicyDefinition.Name

                [pscustomobject] $TemplateObject = @'
                    {
                        "$schema": "",
                        "contentVersion": "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                if ($PolicyDefinitionScope -eq 'Tenant') {
                    [string] $ResourceFilePath = '{0}\.state\{1}' -f $Path, $ResourceFileName
                    [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                } else {
                    [AzBuilderScope] $Item = $AzBuilderScope | Where-Object -Property 'Name' -eq $PolicyDefinitionScope
                    [string] $ResourceFilePath = '{0}\{1}\.state\{2}' -f $Path, $Item.Path, $ResourceFileName

                    if ($Item.Scope -eq 'ManagementGroup') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                    } else {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#'
                    }
                }

                [pscustomobject] $ResourceObject = @'
                    {
                        "type": "Microsoft.Authorization/policyDefinitions",
                        "apiVersion": "2020-03-01",
                        "name": "",
                        "properties": {}
                    }
'@
 | ConvertFrom-Json

                $ResourceObject.name = $PolicyDefinition.Name
                $ResourceObject.properties = $PolicyDefinition.Properties

                $TemplateObject.'$schema' = $Schema
                $TemplateObject.resources = @($ResourceObject)

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

                $TemplateObject | ConvertTo-Json -Depth 30 | Out-File -FilePath $ResourceFilePath
            }

            [Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.Policy.PsPolicySetDefinition[]] $PolicySetDefinitions = Get-AzPolicySetDefinition -Custom

            foreach ($PolicySetDefinition in $PolicySetDefinitions) {
                if (-not ($PolicySetDefinition.ResourceId.Split('/')[1] -eq 'subscriptions')) {
                    [string] $PolicySetDefinitionScope = $PolicySetDefinition.ResourceId.Split('/')[4]

                    if ($PolicySetDefinitionScope -match $GuidRegex) {
                        [string] $PolicySetDefinitionScope = 'Tenant'
                    }
                } else {
                    [string] $PolicySetDefinitionScope = $PolicySetDefinition.ResourceId.Split('/')[2]
                }

                [string[]] $ResourceType = $PolicySetDefinition.ResourceType.Split('/')
                [string] $ResourceFileName = '{0}_{1}-{2}.json' -f $ResourceType[0], $ResourceType[1], $PolicySetDefinition.Name

                [pscustomobject] $TemplateObject = @'
                    {
                        "$schema": "",
                        "contentVersion": "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                if ($PolicySetDefinitionScope -eq 'Tenant') {
                    [string] $ResourceFilePath = '{0}\.state\{1}' -f $Path, $ResourceFileName
                    [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                } else {
                    [AzBuilderScope] $Item = $AzBuilderScope | Where-Object -Property 'Name' -eq $PolicySetDefinitionScope
                    [string] $ResourceFilePath = '{0}\{1}\.state\{2}' -f $Path, $Item.Path, $ResourceFileName

                    if ($Item.Scope -eq 'ManagementGroup') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                    } else {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#'
                    }
                }

                [pscustomobject] $ResourceObject = @'
                    {
                        "type": "Microsoft.Authorization/policySetDefinitions",
                        "apiVersion": "2020-03-01",
                        "name": "",
                        "properties": {}
                    }
'@
 | ConvertFrom-Json

                $ResourceObject.name = $PolicySetDefinition.Name
                $ResourceObject.properties = $PolicySetDefinition.Properties

                $TemplateObject.'$schema' = $Schema
                $TemplateObject.resources = @($ResourceObject)

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

                $TemplateObject | ConvertTo-Json -Depth 30 | Out-File -FilePath $ResourceFilePath -Force
            }

            [Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.Policy.PsPolicyAssignment[]] $PolicyAssignments = Get-AzPolicyAssignment

            foreach ($PolicyAssignment in $PolicyAssignments) {
                if (-not ($PolicyAssignment.ResourceId.Split('/')[1] -eq 'subscriptions')) {
                    [string] $PolicyAssignmentScope = $PolicyAssignment.ResourceId.Split('/')[4]

                    if ($PolicyAssignmentScope -match $GuidRegex) {
                        [string] $PolicyAssignmentScope = 'Tenant'
                    }
                } else {
                    [string] $PolicyAssignmentScope = $PolicyAssignment.ResourceId.Split('/')[2]
                }

                [string[]] $ResourceType = $PolicyAssignment.ResourceType.Split('/')
                [string] $ResourceFileName = '{0}_{1}-{2}.json' -f $ResourceType[0], $ResourceType[1], $PolicyAssignment.Name

                [pscustomobject] $TemplateObject = @'
                    {
                        "$schema": "",
                        "contentVersion": "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                if ($PolicyAssignmentScope -eq 'Tenant') {
                    [string] $ResourceFilePath = '{0}\.state\{1}' -f $Path, $ResourceFileName
                    [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                } else {
                    [AzBuilderScope] $Item = $AzBuilderScope | Where-Object -Property 'Name' -eq $PolicyAssignmentScope
                    [string] $ResourceFilePath = '{0}\{1}\.state\{2}' -f $Path, $Item.Path, $ResourceFileName

                    if ($Item.Scope -eq 'ManagementGroup') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                    } else {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#'
                    }
                }

                [pscustomobject] $ResourceObject = @'
                    {
                        "type": "Microsoft.Authorization/policyAssignments",
                        "apiVersion": "2020-03-01",
                        "name": "",
                        "properties": {}
                    }
'@
 | ConvertFrom-Json

                $ResourceObject.name = $PolicyAssignment.Name
                $ResourceObject.properties = $PolicyAssignment.Properties

                $TemplateObject.'$schema' = $Schema
                $TemplateObject.resources = @($ResourceObject)

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

                $TemplateObject | ConvertTo-Json -Depth 30 | Out-File -FilePath $ResourceFilePath -Force
            }

            [Microsoft.Azure.Commands.Resources.Models.Authorization.PSRoleDefinition[]] $RoleDefinitions = Get-AzRoleDefinition -Custom

            foreach ($RoleDefinition in $RoleDefinitions) {
                if (-not ($RoleDefinition.AssignableScopes[0].Split('/')[1] -eq 'subscriptions')) {
                    [string] $RoleDefinitionScope = $RoleDefinition.AssignableScopes[0].Split('/')[4]

                    if ($RoleDefinitionScope -match $GuidRegex) {
                        [string] $RoleDefinitionScope = 'Tenant'
                    }
                } else {
                    if (-not ($RoleDefinition.AssignableScopes[0].Split('/')[3] -eq 'resourceGroups')) {
                        [string] $RoleDefinitionScope = $RoleDefinition.AssignableScopes[0].Split('/')[2]
                    } else {
                        [string] $RoleDefinitionScope = $RoleDefinition.AssignableScopes[0].Split('/')[4]
                    }
                }

                [string] $ResourceFileName = 'Microsoft.Authorization_roleDefinitions-{0}.json' -f $RoleDefinition.Name

                [pscustomobject] $TemplateObject = @'
                    {
                        "$schema": "",
                        "contentVersion": "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                if ($RoleDefinitionScope -eq 'Tenant') {
                    [string] $ResourceFilePath = '{0}\.state\{1}' -f $Path, $ResourceFileName
                    [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                } else {
                    [AzBuilderScope] $Item = $AzBuilderScope | Where-Object -Property 'Name' -eq $RoleDefinitionScope
                    [string] $ResourceFilePath = '{0}\{1}\.state\{2}' -f $Path, $Item.Path, $ResourceFileName

                    if ($Item.Scope -eq 'ManagementGroup') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                    } elseif ($Item.Scope -eq 'Subscription') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#'
                    } else {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
                    }
                }

                [pscustomobject] $ResourceObject = @'
                    {
                        "type": "Microsoft.Authorization/roleDefinitions",
                        "apiVersion": "2018-01-01-preview",
                        "name": "",
                        "properties": {
                            "roleName": "",
                            "description": "",
                            "permissions": [
                                {
                                    "actions": [],
                                    "notActions": [],
                                    "dataActions": [],
                                    "notDataActions": []
                                }
                            ],
                            "assignableScopes": []
                        }
                    }
'@
 | ConvertFrom-Json

                $ResourceObject.name = $RoleDefinition.Name
                $ResourceObject.properties.roleName = $RoleDefinition.Name
                $ResourceObject.properties.description = $RoleDefinition.Description
                $ResourceObject.properties.permissions[0].actions = $RoleDefinition.Actions
                $ResourceObject.properties.permissions[0].notActions = $RoleDefinition.NotActions
                $ResourceObject.properties.permissions[0].dataActions = $RoleDefinition.DataActions
                $ResourceObject.properties.permissions[0].notDataActions = $RoleDefinition.NotDataActions
                $ResourceObject.properties.assignableScopes = $RoleDefinition.AssignableScopes

                $TemplateObject.'$schema' = $Schema
                $TemplateObject.resources = @($ResourceObject)

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

                $TemplateObject | ConvertTo-Json -Depth 30 | Out-File -FilePath $ResourceFilePath -Force
            }

            [Microsoft.Azure.Commands.Resources.Models.Authorization.PSRoleAssignment[]] $RoleAssignments = Get-AzRoleAssignment

            foreach ($RoleAssignment in $RoleAssignments) {
                if (-not ($RoleAssignment.Scope.Split('/')[1] -eq 'subscriptions')) {
                    [string] $RoleAssignmentScope = $RoleAssignment.Scope.Split('/')[4]

                    if ($RoleAssignmentScope -match $GuidRegex) {
                        [string] $RoleAssignmentScope = 'Tenant'
                    }
                } else {
                    if (-not ($RoleAssignment.Scope.Split('/')[3] -eq 'resourceGroups')) {
                        [string] $RoleAssignmentScope = $RoleAssignment.Scope.Split('/')[2]
                    } else {
                        [string] $RoleAssignmentScope = $RoleAssignment.Scope.Split('/')[4]
                    }

                }

                [string] $ResourceFileName = 'Microsoft.Authorization_roleAssignments-{0}.json' -f $RoleAssignment.DisplayName

                [pscustomobject] $TemplateObject = @'
                    {
                        "$schema": "",
                        "contentVersion": "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                if ($RoleDefinitionScope -eq 'Tenant') {
                    [string] $ResourceFilePath = '{0}\.state\{1}' -f $Path, $ResourceFileName
                    [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                } else {
                    [AzBuilderScope] $Item = $AzBuilderScope | Where-Object -Property 'Name' -eq $RoleAssignmentScope
                    [string] $ResourceFilePath = '{0}\{1}\.state\{2}' -f $Path, $Item.Path, $ResourceFileName

                    if ($Item.Scope -eq 'ManagementGroup') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                    } elseif ($Item.Scope -eq 'Subscription') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#'
                    } else {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
                    }
                }

                [pscustomobject] $ResourceObject = @'
                    {
                        "type": "Microsoft.Authorization/roleAssignments",
                        "apiVersion": "2020-04-01-preview",
                        "name": "",
                        "scope": "",
                        "properties": {
                            "roleDefinitionId": "",
                            "principalId": "",
                            "principalType": "",
                            "canDelegate": "",
                            "description": "",
                            "condition": "",
                            "conditionVersion": ""
                        }
                    }
'@
 | ConvertFrom-Json

                $ResourceObject.name = $RoleAssignment.DisplayName
                $ResourceObject.scope = $RoleAssignment.Scope
                $ResourceObject.properties.roleDefinitionId = $RoleAssignment.RoleDefinitionId
                $ResourceObject.properties.principalId = $RoleAssignment.ObjectId
                $ResourceObject.properties.principalType = $RoleAssignment.ObjectType
                $ResourceObject.properties.canDelegate = $RoleAssignment.CanDelegate
                $ResourceObject.properties.description = $RoleAssignment.Description
                $ResourceObject.properties.condition = $RoleAssignment.Condition
                $ResourceObject.properties.conditionVersion = $RoleAssignment.ConditionVersion

                $TemplateObject.'$schema' = $Schema
                $TemplateObject.resources = @($ResourceObject)

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

                $TemplateObject | ConvertTo-Json -Depth 30 | Out-File -FilePath $ResourceFilePath -Force
            }

            [Microsoft.Azure.Commands.Blueprint.Models.PSBlueprint[]] $Blueprints = Get-AzBlueprint

            foreach ($Blueprint in $Blueprints) {

                if (-not ($Blueprint.Scope.Split('/')[1] -eq 'subscriptions')) {
                    [string] $BlueprintScope = $Blueprint.Scope.Split('/')[4]

                    if ($BlueprintScope -match $GuidRegex) {
                        [string] $BlueprintScope = 'Tenant'
                    }
                } else {
                    [string] $BlueprintScope = $Blueprint.Scope.Split('/')[2]
                }

                [string] $ResourceFileName = 'Microsoft.Blueprint_blueprints-{0}.json' -f $Blueprint.Name

                [pscustomobject] $TemplateObject = @'
                    {
                        "$schema": "",
                        "contentVersion": "1.0.0.0",
                        "parameters": {},
                        "variables": {},
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                if ($BlueprintScope -eq 'Tenant') {
                    [string] $ResourceFilePath = '{0}\.state\{1}' -f $Path, $ResourceFileName
                    [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                } else {
                    [AzBuilderScope] $Item = $AzBuilderScope | Where-Object -Property 'Name' -eq $BlueprintScope
                    [string] $ResourceFilePath = '{0}\{1}\.state\{2}' -f $Path, $Item.Path, $ResourceFileName

                    if ($Item.Scope -eq 'ManagementGroup') {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2019-08-01/managementGroupDeploymentTemplate.json#'
                    } else {
                        [string] $Schema = 'https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#'
                    }
                }

                [pscustomobject] $ResourceObject = @'
                    {
                        "type": "Microsoft.Blueprint/blueprints",
                        "apiVersion": "2018-11-01-preview",
                        "name": "",
                        "properties": {
                            "displayName": "",
                            "description": "",
                            "targetScope": "",
                            "parameters": {},
                            "resourceGroups": {},
                            "versions": {},
                            "layout": {}
                        },
                        "resources": []
                    }
'@
 | ConvertFrom-Json

                $ResourceObject.name = $Blueprint.Name
                $ResourceObject.properties.displayName = $Blueprint.Name
                $ResourceObject.properties.description = $Blueprint.Description
                $ResourceObject.properties.targetScope = $Blueprint.TargetScope
                $ResourceObject.properties.parameters = $Blueprint.Parameters
                $ResourceObject.properties.resourceGroups = $Blueprint.ResourceGroups
                $ResourceObject.properties.versions = $Blueprint.Versions
                $ResourceObject.properties.layout = $Blueprint.ConditionVersion

                if (Test-Path -Path $TemporaryPath) {
                    $null = Remove-Item -Path $TemporaryPath -Recurse -Force
                }

                $null = New-Item -Path $TemporaryPath -ItemType 'Directory'

                $null = Export-AzBlueprintWithArtifact -Blueprint $Blueprint -OutputPath $TemporaryPath

                [string] $BlueprintArtifactsPath = '{0}\{1}\Artifacts' -f $TemporaryPath, $Blueprint.Name
                [System.IO.FileInfo[]] $ArtifactTemplates = Get-ChildItem -Path $BlueprintArtifactsPath -Filter '*.json'

                if ($ArtifactTemplates) {
                    [System.Collections.Generic.List[pscustomobject]] $ArtifactsList = @()

                    foreach ($TemplateFile in $ArtifactTemplates) {
                        [pscustomobject] $ArtifactResourceObject = @'
                            {
                                "type": "artifacts",
                                "apiVersion": "2018-11-01-preview",
                                "name": "",
                                "kind": "",
                                "dependsOn": [],
                                "properties": {}
                            }
'@
 | ConvertFrom-Json

                        [pscustomobject] $ArtifactObject = Get-Content -Path $TemplateFile.FullName | ConvertFrom-Json

                        $ArtifactResourceObject.name = $TemplateFile.BaseName
                        $ArtifactResourceObject.kind = $ArtifactObject.kind
                        $ArtifactResourceObject.dependsOn = @($ResourceObject.name)
                        $ArtifactResourceObject.properties = $ArtifactObject.properties

                        $ArtifactsList.Add($ArtifactResourceObject)
                    }

                    $ResourceObject.resources = $ArtifactsList
                }

                $TemplateObject.'$schema' = $Schema
                $TemplateObject.resources = @($ResourceObject)

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

                $TemplateObject | ConvertTo-Json -Depth 30 | Out-File -FilePath $ResourceFilePath -Force

                if (Test-Path -Path $TemporaryPath) {
                    $null = Remove-Item -Path $TemporaryPath -Recurse -Force
                }
            }

            foreach ($Item in ($AzBuilderScope | Where-Object -FilterScript {$_.Scope -eq 'ResourceGroup' -and $_.Parent -eq $Subscription.Id})) {
                [Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResource[]] $Resources = Get-AzResource -ResourceGroupName $Item.Name

                foreach ($Resource in $Resources) {
                    [string[]] $ResourceType = $Resource.Type.Split('/')
                    [string] $ResourceFileName = '{0}_{1}-{2}.json' -f $ResourceType[0], $ResourceType[1], $Resource.Name
                    [string] $ResourceFilePath = '{0}\{1} ({2})\.state\{3}' -f $Path, $Item.Path, $Item.Location, $ResourceFileName

                    $null = Export-AzResourceGroup -Resource $Resource.Id -Path $ResourceFilePath -ResourceGroupName $Resource.ResourceGroupName -SkipAllParameterization -Force
                }
            }
        }
    } catch {
        $PSCmdlet.ThrowTerminatingError($PSItem)
    }
}