Public/Add-FinOpsServicePrincipal.ps1
<#
.SYNOPSIS Grants the specified service principal or managed identity access to an Enterprise Agreement billing account or department. .PARAMETER ObjectId The object ID of the service principal or managed identity. .PARAMETER TenantId The Azure Active Directory tenant which contains the identity. .PARAMETER BillingScope Specifies whether to grant permissions at an enrollment or department level. .PARAMETER BillingAccountId The billing account ID (enrollment number) to grant permissions against. .PARAMETER DepartmentId The department ID to grant permissions against. .EXAMPLE Add-FinOpsServicePrincipal -ObjectId 00000000-0000-0000-0000-000000000000 -TenantId 00000000-0000-0000-0000-000000000000 -BillingScope Enrollment -BillingAccountId 12345 Grants EA Reader permissions to the specified service principal or managed identity .EXAMPLE Add-FinOpsServicePrincipal -ObjectId 00000000-0000-0000-0000-000000000000 -TenantId 00000000-0000-0000-0000-000000000000 -BillingScope Department -BillingAccountId 12345 -DepartmentId 67890 Grants department reader permissions to the specified service principal or managed identity #> function Add-FinOpsServicePrincipal { param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$ObjectId, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$TenantId, [Parameter(Mandatory = $true)] [string]$BillingAccountId, [Parameter(Mandatory = $false)] [string]$DepartmentId ) $azContext = Get-AzContext if (![string]::IsNullOrEmpty($DepartmentId) -and ![string]::IsNullOrEmpty($BillingAccountId)) { $BillingScope = 'Department' } elseif ([string]::IsNullOrEmpty($DepartmentId) -and ![string]::IsNullOrEmpty($BillingAccountId)) { $BillingScope = 'Enrollment' } else { throw ($LocalizedData.ServicePrincipal_BillingAccountNotSpecified) } switch ($BillingScope) { 'Enrollment' { if ([string]::IsNullOrEmpty($BillingAccountId)) { Write-Output $LocalizedData.ServicePrincipal_BillingAccountNotSpecifiedForDept Write-Output '' exit 1 } $roleDefinitionId = "/providers/Microsoft.Billing/billingAccounts/{0}/billingRoleDefinitions/24f8edb6-1668-4659-b5e2-40bb5f3a7d7e" -f $BillingAccountId $restUri = "{0}providers/Microsoft.Billing/billingAccounts/{1}/billingRoleAssignments/{2}?api-version=2019-10-01-preview" -f $azContext.Environment.ResourceManagerUrl, $BillingAccountId, (New-Guid).Guid $body = '{"properties": { "PrincipalId": "{0}", "PrincipalTenantId": "{1}", "roleDefinitionId": "{2}" } }' $body = $body.Replace("{0}", $ObjectId) $body = $body.Replace("{1}", $TenantId) $body = $body.Replace("{2}", $roleDefinitionId) } 'Department' { if ([string]::IsNullOrEmpty($BillingAccountId)) { Write-Output $LocalizedData.ServicePrincipal_BillingAccountNotSpecifiedForDept Write-Output '' exit 1 } if ([string]::IsNullOrEmpty($DepartmentId)) { Write-Output $LocalizedData.ServicePrincipal_DeptIdNotSpecified Write-Output '' exit 1 } $roleDefinitionId = "/providers/Microsoft.Billing/billingAccounts/{0}/departments/{1}/billingRoleDefinitions/db609904-a47f-4794-9be8-9bd86fbffd8a" -f $BillingAccountId, $DepartmentId $restUri = "{0}providers/Microsoft.Billing/billingAccounts/{1}/departments/{2}/billingRoleAssignments/{3}?api-version=2019-10-01-preview" -f $azContext.Environment.ResourceManagerUrl, $BillingAccountId, $DepartmentId, (New-Guid).Guid $body = '{"properties": { "PrincipalId": "{0}", "PrincipalTenantId": "{1}", "roleDefinitionId": "{2}" } }' $body = $body.Replace("{0}", $ObjectId) $body = $body.Replace("{1}", $TenantId) $body = $body.Replace("{2}", $roleDefinitionId) } default { throw ($LocalizedData.ServicePrincipal_InvalidBillingScope -f $BillingScope) } } $azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile $profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azProfile) $token = $profileClient.AcquireAccessToken($azContext.Subscription.TenantId) $authHeader = @{ 'Content-Type' = 'application/json' 'Authorization' = 'Bearer ' + $token.AccessToken } try { # TODO: Switch to Invoke-Rest Invoke-RestMethod -Uri $restUri -Method Put -Headers $authHeader -Body $body Write-Output ($LocalizedData.ServicePrincipal_SuccessMessage -f $BillingScope) } catch { if ($_.Exception.Response.StatusCode -eq 409) { Write-Output ($LocalizedData.ServicePrincipal_AlreadyGrantedMessage -f $BillingScope) } else { $body throw $_.Exception } } } |