Introduction

We want to have a system user that is able to provision subscriptions as part of our vending machine. There's currently no user interface to do this, only some preview APIs from 2019.

The code

[CmdletBinding()]
param (
    [Parameter(Mandatory)]
    [string]
    $IdentityId,

    [Parameter(Mandatory)]
    [string]
    [ValidateSet('SubscriptionCreator', 'DepartmentReader', 'EA purchaser', 'EnrollmentReader')]
    $BillingRole
)

function Get-AzureBillingAccounts {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        $Headers
    )
    $data = (Invoke-RestMethod -Method Get -Uri "https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2019-10-01-preview" -Headers $Headers).value |
    Select-Object Name, @{'N' = 'accountStatus'; 'E' = { $_.properties.accountStatus } },
        @{'N' = 'agreementType'; 'E' = { $_.properties.agreementType } },
        @{'N' = 'displayName'; 'E' = { $_.properties.displayName } }, Id
    Write-Output $data
}

function Get-AzureEnrollmentAccounts {
    [CmdletBinding()]
    param (
        [Parameter()] [string] $BillingAccountName,
        [Parameter(Mandatory)] $Headers
    )
    $data = (Invoke-RestMethod -Method Get -Uri "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$BillingAccountName/enrollmentAccounts?api-version=2019-10-01-preview" -Headers $Headers).value |
    Select-Object Name, @{'N' = 'AccountName'; 'E' = { $_.properties.accountName } },
        @{'N' = 'DisplayName'; 'E' = { $_.properties.displayName } },
        @{'N' = 'Status'; 'E' = { $_.properties.status } }
    Write-Output $data
}

function New-AzureBillingRoleAssignment {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)] $Headers,
        [Parameter(Mandatory)] [ValidateSet('SubscriptionCreator', 'DepartmentReader', 'EA purchaser', 'EnrollmentReader')] [string] $BillingRole,
        [Parameter(Mandatory)] [string] $IdentityId,
        [Parameter(Mandatory)] [string] $BillingAccountName,
        [Parameter(Mandatory)] [string] $EnrollmentAccountName,
        [Parameter(Mandatory)] [string] $TenantId
    )

    begin {
        $BillingRoles = @{
            'SubscriptionCreator' = 'a0bcee42-bf30-4d1b-926a-48d21664ef71'
            'DepartmentReader'    = 'db609904-a47f-4794-9be8-9bd86fbffd8a'
            'EA purchaser'        = 'da6647fb-7651-49ee-be91-c43c4877f0c4'
            'EnrollmentReader'    = '24f8edb6-1668-4659-b5e2-40bb5f3a7d7e'
        }
        $BillingRoleId = $BillingRoles[$BillingRole]
    }

    process {
        $UniqueRoleAssignmentId = (New-guid).Guid
        $RoleAssignmentUrl = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$BillingAccountName/enrollmentAccounts/$EnrollmentAccountName/billingRoleAssignments/$UniqueRoleAssignmentId`?api-version=2019-10-01-preview"
        $Body = @{
            "properties" = @{
                "principalId"       = "$IdentityId"
                "principalTenantId" = "$TenantId"
                "roleDefinitionId"  = "/providers/Microsoft.Billing/billingAccounts/$BillingAccountName/enrollmentAccounts/$EnrollmentAccountName/billingRoleDefinitions/$BillingRoleId"
            }
        } | ConvertTo-Json -depth 100

        try {
            Invoke-RestMethod -Method Put -Uri $RoleAssignmentUrl -Headers $Headers -Body $Body
            Write-verbose "Successfully created the role assignment." -Verbose
        }
        catch { throw }
    }
}

# Use Az PowerShell Module token
$token = $(Get-AzAccessToken).Token
$headers = @{'Authorization' = "Bearer $Token"; 'Content-Type' = 'application/json' }
$TenantId = (get-azcontext).tenant.id

# Interactive selection
$BillingAccount = Get-AzureBillingAccounts -Headers $headers | Out-GridView -PassThru
$EnrollmentAccount = Get-AzureEnrollmentAccounts -BillingAccountName $BillingAccount.Name -Headers $headers | Out-GridView -PassThru

$Params = @{
    'Headers' = $headers
    'BillingRole' = $BillingRole
    'IdentityId' = $IdentityId
    'BillingAccountName' = $BillingAccount.Name
    'EnrollmentAccountName' = $EnrollmentAccount.Name
    'TenantId' = $TenantId
}
New-AzureBillingRoleAssignment @Params