AzBluePrint.psm1

Function Get-AzAccessToken() {
    try {
        $azureCtx = Get-AzContext

        $azureProfile  = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
        $profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azureProfile)
        $token         = $profileClient.AcquireAccessToken($azureCtx.Subscription.TenantId)

        $token.AccessToken
    } catch {
        Throw $_
    }
}

Function Get-AzBluePrintResource() {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'managementgroup')]
        [string]
        $ManagementGroupName,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [guid]
        $SubscriptionId,
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

    $SplatGetBlueprint = @{
        Headers = @{
            'Authorization' = 'Bearer {0}' -f (Get-AzAccessToken)
            'Content-Type'  = 'application/json'
        }
        Method          = 'Get'
        UseBasicParsing = $true
    }

    try {
        if ($PSBoundParameters['ManagementGroupName']) {
            $SplatGetBlueprint['URI'] = 'https://management.azure.com/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}?api-version=2018-11-01-preview' -f $ManagementGroupName, $name
        }

        if ($PSBoundParameters['SubscriptionId']) {
            $SplatGetBlueprint['URI'] = 'https://management.azure.com/subscriptions/{0}/providers/Microsoft.Blueprint/blueprints/{1}?api-version=2018-11-01-preview' -f $SubscriptionId, $name
        }

        $bluePrint = Invoke-WebRequest @SplatGetBlueprint | Select-Object -ExpandProperty Content | ConvertFrom-Json

        if ($bluePrint) {
            $bluePrint.PSObject.TypeNames.Insert(0, 'BenTaylorWork.Az.BluePrintResource')

            $bluePrint
        } else {
            Throw 'No usuable blueprint.'
        }
    } catch {
        Write-Error $_
    }
}

Function Get-AzBluePrintArtifact() {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'managementgroup')]
        [string]
        $ManagementGroupName,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [guid]
        $SubscriptionId,
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

    $SplatGetBlueprintArtifact = @{
        Headers = @{
            'Authorization' = 'Bearer {0}' -f (Get-AzAccessToken)
            'Content-Type'  = 'application/json'
        }
        Method          = 'Get'
        UseBasicParsing = $true
    }

    try {
        if ($PSBoundParameters['ManagementGroupName']) {
            $SplatGetBlueprintArtifact['URI'] = 'https://management.azure.com/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}/artifacts?api-version=2018-11-01-preview'  -f $ManagementGroupName, $name
        }

        if ($PSBoundParameters['SubscriptionId']) {
            $SplatGetBlueprintArtifact['URI'] = 'https://management.azure.com/subscriptions/{0}/providers/Microsoft.Blueprint/blueprints/{1}/artifacts?api-version=2018-11-01-preview' -f $SubscriptionId, $name
        }

        $bluePrintArtifact = Invoke-WebRequest @SplatGetBlueprintArtifact | Select-Object -ExpandProperty Content

        if ($bluePrintArtifact) {
            $bluePrintArtifact = $bluePrintArtifact | ConvertFrom-Json | Select-Object -ExpandProperty value

            ForEach($artifact in $bluePrintArtifact) {
                $artifact.PSObject.TypeNames.Insert(0, 'BenTaylorWork.Az.BluePrintArtifact')

                $artifact
            }
        } else {
            Throw 'No usuable blueprint.'
        }
    } catch {
        Write-Error $_
    }
}

Function Export-AzBluePrintResource() {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'bluePrint')]
        [PSTypeName('BenTaylorWork.Az.BluePrintResource')]
        $bluePrint,
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'bluePrintArtifact')]
        [PSTypeName('BenTaylorWork.Az.BluePrintArtifact')]
        $BluePrintArtifact,
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            Test-Path $_
        })]
        [string]
        $path = '.\'
    )

    Process {
        try {
            if ($PSBoundParameters['bluePrint']) {
                $blueprintExportPath = (Join-Path $path ('{0}.json' -f $bluePrint.Name))

                if (Test-Path $blueprintExportPath) {
                    Throw 'Export file allready exists.'
                } else {
                    $bluePrint | ConvertTo-Json -Depth 100 | Out-File -FilePath $blueprintExportPath
                }
            }

            if ($PSBoundParameters['BluePrintArtifact']) {
                $blueprintArtifactExportPath = (Join-Path $path ('{0}.json' -f $BluePrintArtifact.Name))

                if (Test-Path $blueprintArtifactExportPath) {
                    Throw 'Artifact Export file allready exists, skipping file'
                } else {
                    $BluePrintArtifact | ConvertTo-Json -Depth 100 | Out-File -FilePath $blueprintArtifactExportPath
                }
            }
        } catch {
            Write-Error $_
        }
    }
}

Function Export-AzBluePrint() {
    [CmdletBinding()]
    <#
        .SYNOPSIS
            Exports an Azure blueprint with the associated artifacts.
        .EXAMPLE
            Export-AzBluePrint -ManagementGroupName '<management-group-name>' -Name '<blueprint-name>'
        .NOTES
            Written by Ben Taylor
            Version 1.0.0.0, 10.01.2019
    #>

    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'bluePrint')]
        [PSTypeName('Microsoft.Azure.Commands.Blueprint.Models.PSBlueprint')]
        $bluePrint,
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $ManagementGroupName,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $Name,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [guid]
        $SubscriptionId,
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            Test-Path $_
        })]
        [string]
        $path = '.\'
    )

    Process {
        try {
            if ($PSBoundParameters['bluePrint']) {
                $Name = $bluePrint.name

                if ($bluePrint.id.Contains('subscriptions')) {
                    $SubscriptionId = ($bluePrint.id -split '/')[2]

                    $bluePrint = Get-AzBluePrintResource -SubscriptionId $SubscriptionId -Name $Name
                } else {
                    $ManagementGroupName = ($bluePrint.id -split '/')[4]

                    $bluePrint = Get-AzBluePrintResource -ManagementGroupName $ManagementGroupName -Name $Name
                }
            }

            if ($PSBoundParameters['ManagementGroupName']) {
                $bluePrint = Get-AzBluePrintResource -ManagementGroupName $ManagementGroupName -Name $Name
            }

            if ($PSBoundParameters['SubscriptionId']) {
                $bluePrint = Get-AzBluePrintResource -SubscriptionId $SubscriptionId -Name $Name
            }

            $baseExportPath = Join-Path $path $bluePrint.Name

            if (-not (Test-Path $baseExportPath)) {
                New-Item -ItemType Directory -Path $path -Name ($bluePrint.Name) | Out-Null
                $artifactPath = (New-Item -ItemType Directory -Path  $baseExportPath -Name 'Artifacts').FullName
            } else {
                Throw 'Base export path allready exists.'
            }

            $bluePrint | Export-AzBluePrintResource -path $baseExportPath

            if ($bluePrint.id.Contains('subscriptions')) {
                $bluePrintArtifacts = Get-AzBluePrintArtifact -SubscriptionId $SubscriptionId -Name $Name
            } else {
                $bluePrintArtifacts = Get-AzBluePrintArtifact -ManagementGroupName $ManagementGroupName -Name $Name
            }

            if ($bluePrintArtifacts) {
                $bluePrintArtifacts | Export-AzBluePrintResource -path $artifactPath
            }
        } catch {
            Write-Error $_
        }
    }
}

Function Import-AzBluePrintResource() {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]
        [ValidateScript({
            Test-Path $_
        })]
        $path,
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $ManagementGroupName,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $Name,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [guid]
        $SubscriptionId
    )

    process {
        try {
            $bluePrint = Get-Content -Path $path | ConvertFrom-Json

            $bluePrint.name = $Name

            if ($PSBoundParameters['ManagementGroupName']) {
                $bluePrint.id = '/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}' -f $ManagementGroupName, $Name
            }

            if ($PSBoundParameters['SubscriptionId']) {
                $bluePrint.id = '/subscriptions/{0}/providers/Microsoft.Blueprint/blueprints/{1}' -f $SubscriptionId, $Name
            }

            $SplatPutBlueprint = @{
                Headers = @{
                    'Authorization' = 'Bearer {0}' -f (Get-AzAccessToken)
                    'Content-Type'  = 'application/json'
                }
                Method          = 'PUT'
                UseBasicParsing = $true
                URI             = ('https://management.azure.com{0}?api-version=2018-11-01-preview' -f $bluePrint.id)
                Body            = $bluePrint | ConvertTo-Json -depth 100 -Compress
                ErrorAction     = 'Stop'
            }

            Invoke-WebRequest @SplatPutBlueprint | Out-Null
        } catch {
            Write-Error $_
        }
    }
}

Function Import-AzBluePrintArtifactResource() {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]
        [ValidateScript({
            Test-Path $_
        })]
        $path,
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $ManagementGroupName,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $Name,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [guid]
        $SubscriptionId
    )

    process {
        $artifact = Get-Content -path $path | ConvertFrom-Json

        if ($PSBoundParameters['ManagementGroupName']) {
            $artifact.id = '/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}/artifacts/{2}' -f $ManagementGroupName, $Name,  $artifact.name
        }

        if ($PSBoundParameters['SubscriptionId']) {
            $bluePrint.id = '/subscriptions/{0}/providers/Microsoft.Blueprint/blueprints/{1}/artifacts/{2}' -f $SubscriptionId, $Name,  $artifact.name
        }

        $SplatPutBlueprintArtifact = @{
            Headers = @{
                'Authorization' = 'Bearer {0}' -f (Get-AzAccessToken)
                'Content-Type'  = 'application/json'
            }
            Method          = 'PUT'
            UseBasicParsing = $true
            URI             = ('https://management.azure.com{0}?api-version=2018-11-01-preview' -f $artifact.id)
            Body            = $artifact | ConvertTo-Json -depth 100 -Compress
            ErrorAction     = 'Stop'
        }

        Invoke-WebRequest @SplatPutBlueprintArtifact | Out-Null
    }
}

Function Import-AzBluePrint() {
    <#
        .SYNOPSIS
            Imports an Azure blueprint from the exported files.
        .EXAMPLE
            Import-AzBluePrint -ManagementGroupName '<management-group-name>' -Name '<blueprint-name>'
        .EXAMPLE
            Import-AzBluePrint -ManagementGroupName '<management-group-name>' -Name '<blueprint-name>' -path 'c:\blueprints'
        .NOTES
            Written by Ben Taylor
            Version 1.0.0.0, 10.01.2019
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ParameterSetName = 'managementGroup')]
        [string]
        $ManagementGroupName,
        [Parameter(Mandatory = $true, ParameterSetName = 'subscription')]
        [guid]
        $SubscriptionId,
        [Parameter(Mandatory = $true)]
        [string]
        $Name,
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            Test-Path $_
        })]
        [string]
        $path = '.\'
    )

    try {
        $blueprintImportBasePath = Join-Path $path $Name

        If (-not (Test-Path $blueprintImportBasePath)) {
            Throw 'No Aritifact template found to import.'
        }

        $blueprintResourceSplat = @{
            Name               = $Name
            Path               = Join-Path $blueprintImportBasePath ('{0}.json' -f $Name)
        }

        $blueprintResourceArtifactSplat = @{
            Name = $Name
        }

        if ($PSBoundParameters['ManagementGroupName']) {
            $blueprintResourceSplat['ManagementGroupName']         = $ManagementGroupName
            $blueprintResourceArtifactSplat['ManagementGroupName'] = $ManagementGroupName
        }

        if ($PSBoundParameters['SubscriptionId']) {
            $blueprintResourceSplat['SubscriptionId']         = $SubscriptionId
            $blueprintResourceArtifactSplat['SubscriptionId'] = $SubscriptionId
        }

        Import-AzBluePrintResource @blueprintResourceSplat

        $artifacts = Get-ChildItem -Path (Join-Path $path ('{0}/Artifacts' -f $name))

        if ($artifacts) {
            foreach($artifact in $artifacts) {
                $blueprintResourceArtifactSplat['Path'] = $artifact.FullName

                Import-AzBluePrintArtifactResource @blueprintResourceArtifactSplat
            }
        }
    } catch {
        Write-Error $_
    }
}