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-AzBluePrint() {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $MangementGroupName,
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

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

    try {
        $SplatGetBlueprint['URI'] = 'https://management.azure.com/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}?api-version=2017-11-11-preview' -f $mangementGroupName, $name

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

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

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

Function Get-AzBluePrintArtifact() {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        $MangementGroupName,
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

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

    try {
        $SplatGetBlueprintArtifact['URI'] = 'https://management.azure.com/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}/artifacts?api-version=2017-11-11-preview'  -f $mangementGroupName, $name

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

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

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

Function Export-AzBluePrintResource() {
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'bluePrint')]
        [PSTypeName('BenTaylorWork.Az.BluePrint')]
        $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() {
    <#
        .SYNOPSIS
            Exports an Azure blueprint with the associated artifacts.
        .EXAMPLE
            Export-AzBluePrint -MangementGroupName '<management-group-name>' -Name '<blueprint-name>'
        .NOTES
            Written by Ben Taylor
            Version 1.0.0.0, 10.01.2019
    #>

    param(
        [Parameter(Mandatory = $true)]
        [string]
        $MangementGroupName,
        [Parameter(Mandatory = $true)]
        [string]
        $Name,
        [Parameter(Mandatory = $false)]
        [ValidateScript({
            Test-Path $_
        })]
        [string]
        $path = '.\'
    )

    try {
        $bluePrint = Get-AzBluePrint -mangementGroupName $MangementGroupName -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

        Get-AzBluePrintArtifact -mangementGroupName $MangementGroupName -Name $Name | Export-AzBluePrintResource -path $artifactPath
    } catch {
        Write-Error $_
    }
}

Function Import-AzBluePrintResource() {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        [ValidateScript({
            Test-Path $_
        })]
        $path,
        [Parameter(Mandatory = $true)]
        [string]
        $MangementGroupName,
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

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

            $bluePrint.name   = $Name
            $bluePrint.id     = '/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}' -f $MangementGroupName, $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=2017-11-11-preview' -f $bluePrint.id)
                Body            = $bluePrint | ConvertTo-Json -depth 100 -Compress
                ErrorAction     = 'Stop'
            }

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

Function Import-AzBluePrintArtifactResource() {
    param(
        [Parameter(Mandatory = $true)]
        [string]
        [ValidateScript({
            Test-Path $_
        })]
        $path,
        [Parameter(Mandatory = $true)]
        [string]
        $MangementGroupName,
        [Parameter(Mandatory = $true)]
        [string]
        $Name
    )

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

        $artifact.id = ('/providers/Microsoft.Management/managementGroups/{0}/providers/Microsoft.Blueprint/blueprints/{1}/artifacts/{2}' -f $MangementGroupName, $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=2017-11-11-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 -MangementGroupName '<management-group-name>' -Name '<blueprint-name>'
        .EXAMPLE
            Import-AzBluePrint -MangementGroupName '<management-group-name>' -Name '<blueprint-name>' -path 'c:\blueprints'
        .NOTES
            Written by Ben Taylor
            Version 1.0.0.0, 10.01.2019
    #>

    param(
        [Parameter(Mandatory = $true)]
        [string]
        $MangementGroupName,
        [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
            MangementGroupName = $MangementGroupName
            Path               = Join-Path $blueprintImportBasePath ('{0}.json' -f $Name)
        }

        Import-AzBluePrintResource @blueprintResourceSplat

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

        if ($artifacts) {
            foreach($artifact in $artifacts) {
                $blueprintResourceArtifactSplat = @{
                    Name               = $Name
                    MangementGroupName = $MangementGroupName
                    Path               = $artifact.FullName
                }

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