Public/New-AzDevOpsBlueprintAssignment.ps1

function New-AzDevOpsBlueprintAssignment
{
    <#
    .SYNOPSIS
        Assigns a Blueprint in Azure

    .DESCRIPTION
        Assigns a version of a Blueprint that was published to a Management Group / Subscription

    .PARAMETER Blueprint
        An Object containing the Blueprint information.

    .PARAMETER AssignmentName
        A string containing the Assignment Name of the Blueprint

    .PARAMETER InputPath
        A string containing the path to the Blueprint JSON File e.g.
        'C:\Repos\Blueprints\Small_ISO27001_Shared-Services'

    .PARAMETER Location
        A string containing the azure region name to assign/create the resources for the Blueprint e.g. australiasoutheast

    .PARAMETER Version
        A string containing the Version of the Blueprint to be assigned. This value should be the Release Number generated by the Release pipeline e.g. 20190701.1 YYYYMMDD.R (YYYY - Year, MM = Month, DD = Day, R = Release number)

    .EXAMPLE Assign Blueprint to Subscription
        $Context = Get-AzContext
        $Blueprint = Get-AzBlueprint -Name "Assignment-Small_ISO27001_Shared-Services" -Subscription $Context.Subscription.Id
        New-AzDevOpsBlueprintAssignment `
            -Blueprint $Blueprint `
            -AssignmentName "Assignment-Small_ISO27001_Shared-Services" `
            -InputPath "C:\Repos\Blueprints\Small_ISO27001_Shared-Services" `
            -Location "australiasoutheast" `
            -Version "20190901.001"

    .EXAMPLE Assign Blueprint to Management Group
        $ManagementGroup = Get-AzManagementGroup | Where-Object DisplayName -eq "Development"
        $Blueprint = Get-AzBlueprintAssignment -Name "Assignment-Small_ISO27001_Shared-Services" -ManagementGroupId $ManagementGroup.Name
        New-AzDevOpsBlueprintAssignment `
            -Blueprint $Blueprint `
            -AssignmentName "Assignment-Small_ISO27001_Shared-Services" `
            -InputPath "C:\Repos\Blueprints\Small_ISO27001_Shared-Services" `
            -Location "australiasoutheast" `
            -Version "20190901.001"
    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'None')]
    param
    (
        [parameter(Mandatory=$true)]
        $Blueprint,

        [parameter(Mandatory=$true)]
        [string]$AssignmentName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [ValidateScript({Get-ChildItem -Path $_})]
        [string]$InputPath,

        [Parameter(Mandatory=$true)]
        [string]$Location,

        [Parameter(Mandatory=$true)]
        [string]$Version
    )

    function Confirm-Assignment
    {
        param
        (
            [parameter(Mandatory=$true)]
            $Blueprint,

            [parameter(Mandatory=$true)]
            $AssignmentName
        )

        Do
        {
            switch ($Blueprint)
            {
                {$Blueprint.SubscriptionId}
                {
                    $Assignment = Get-AzBlueprintAssignment -Name $AssignmentName -Subscription $Blueprint.SubscriptionId
                    break
                }

                {$Blueprint.ManagementGroupId}
                {
                    $Assignment = Get-AzBlueprintAssignment -Name $AssignmentName -ManagementGroupId $Blueprint.ManagementGroupId
                    break
                }
            }
            if ($Assignment.ProvisioningState) {    Write-Output $Assignment.ProvisioningState    }
            Start-Sleep -Seconds 5
        } Until (($Assignment.ProvisioningState -eq "Succeeded") -or ($Assignment.ProvisioningState -eq "Failed"))

        switch ($Assignment.ProvisioningState)
        {
            "Succeeded"
            {
                Write-Output "SUCCESS! Blueprint '$($Blueprint.Name) Version '$($Version)' has been Assigned"
                break
            }

            "Failed"
            {
                Write-Output "Error! Blueprint '$($Blueprint.Name) Version '$($Version)' failed"
                throw (Resolve-AzError -Last)
                break
            }

            default
            {
                throw "Unhandled terminal state for assignment: {0}" -f $assignment.ProvisioningState
            }
        }
    }

    try
    {
        # Checking if Commandlet is running on Azure DevOps
        if (!$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI) {
            Write-Warning "It appears you are not running this command inside a job in Azure DevOps."
            Write-Warning "This command is designed to run as a job in Azure DevOps. See https://dev.azure.com/paulrtowler/Az.DevOps.Blueprint for more information."
            Write-Warning "Exiting...`r`n" -ErrorAction Stop
        }

        # Variables
        $rawBlueprint = Get-Content "$($InputPath)\Blueprint.json" | ConvertFrom-Json -ErrorAction Stop

        # Assign Blueprint
        Write-Output "`r`nAssigning Blueprint '$($Blueprint.Name)' using Version '$($Version)'....."
        Write-Output "Matching Variables to Blueprint Resource Groups and configuring Values....."

        $resourceGroups = Find-AzDevOpsBlueprintParameters -Type ResourceGroups -RawBlueprint $rawBlueprint -Location $Location

        if ($resourceGroups.count -ne 0)
        {
            Write-Output " Found Resource Group Parameters!"

            foreach ($resourceGroup in $resourceGroups)
            {
                Write-Output " Setting Resource Group Name to: $($resourceGroup.Values.Name)"
                Write-Output " Setting Resource location to: $($resourceGroup.Values.Location)`r`n"
            }
        }

        Write-Output "Matching Variables to Blueprint Parameters and configuring Values....."
        $params = Find-AzDevOpsBlueprintParameters -Type Parameters -RawBlueprint $rawBlueprint

        if ($params.count -ne 0)
        {
            Write-Output " Found Parameters!"

            foreach ($param in $params.Keys)
            {
                Write-Output " Setting Parameter: $($param)"
            }
        }

        Write-Output "Matching Variables to Blueprint Secure Parameters and configuring Values....."
        $secureParams = Find-AzDevOpsBlueprintParameters -Type SecureParameters -RawBlueprint $rawBlueprint

        if ($secureParams.count -ne 0)
        {
            Write-Output " Found Secure Parameters!"

            foreach ($param in $secureParams.Keys)
            {
                Write-Output " Setting Parameter: $($param)"
            }
        }

        switch ($Blueprint)
        {
            {$Blueprint.SubscriptionId}
            {
                # Get Any old Assignments
                $oldAssignment = Get-AzBlueprintAssignment -Name $AssignmentName -Subscription $Blueprint.SubscriptionId -ErrorAction SilentlyContinue

                if ($oldAssignment -and $PSCmdlet.ShouldProcess($AssignmentName, 'Proceed.')) {
                    # if yes, *update* the assignment
                    Write-Output "Updating existing assignment....."

                    if ($resourceGroups.Count -ge 1)
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -ErrorAction Stop
                        }
                    } else
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -Parameter $params -ErrorAction Stop
                        }
                    }
                } else
                {
                    # if no assignment, create one
                    Write-Output "Creating new assignment....."

                    if ($resourceGroups.Count -ge 1)
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -ErrorAction Stop
                        }
                    } else
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -SubscriptionId $Blueprint.SubscriptionId -Name $AssignmentName -Parameter $params -ErrorAction Stop
                        }
                    }
                }

                # Confirm Assignment
                Confirm-Assignment -Blueprint $Blueprint -AssignmentName $AssignmentName
                break
            }

            {$Blueprint.ManagementGroupId}
            {
                # Get Any old Assignments
                $oldAssignment = Get-AzBlueprintAssignment -Name $AssignmentName -ManagementGroupId $Blueprint.ManagementGroupId -ErrorAction SilentlyContinue

                if ($oldAssignment -and $PSCmdlet.ShouldProcess($AssignmentName, 'Proceed.')) {
                    # if yes, *update* the assignment
                    Write-Output "Updating existing assignment....."

                    if ($resourceGroups.Count -ge 1)
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -ErrorAction Stop
                        }
                    } else
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            Set-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -Parameter $params -ErrorAction Stop
                        }
                    }
                } else
                {
                    # if no assignment, create one
                    Write-Output "Creating new assignment....."

                    if ($resourceGroups.Count -ge 1)
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -ResourceGroupParameter $resourceGroups -Parameter $params -ErrorAction Stop
                        }
                    } else
                    {
                        if ($secureParams.Count -ge 1)
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -Parameter $params -SecureStringParameter $secureParams -ErrorAction Stop
                        } else
                        {
                            New-AzBlueprintAssignment -Blueprint $Blueprint -Location $Location -ManagementGroupId $Blueprint.ManagementGroupId -Name $AssignmentName -Parameter $params -ErrorAction Stop
                        }
                    }
                }

                # Confirm Assignment
                Confirm-Assignment -Blueprint $Blueprint -AssignmentName $AssignmentName
                break
            }
        }
    }
    catch
    {
        if ($_.ErrorDetails.Message) {$ErrDetails = $_.ErrorDetails.Message } else {$ErrDetails = $_}
        if ($_.Message) {$ErrDetails = $_.Message } else {$ErrDetails = $_}
        Get-StandardError -Exception $($ErrDetails)
    }
}