Skip to content

Instantly share code, notes, and snippets.

@joerodgers
Last active June 5, 2026 18:05
Show Gist options
  • Select an option

  • Save joerodgers/c2a56a5328ba2c2bd7d586eaf03a589d to your computer and use it in GitHub Desktop.

Select an option

Save joerodgers/c2a56a5328ba2c2bd7d586eaf03a589d to your computer and use it in GitHub Desktop.
Creates a report mapping Power Platform environments to billing policies. Includes PAYGO details of each billing policy.
#requires -modules "Microsoft.PowerApps.Administration.PowerShell"
function Get-BillingPolicyEnvironmentMap
{
[CmdletBinding()]
param
(
)
begin
{
$accessToken = Get-JwtToken -Audience "https://licensing.powerplatform.microsoft.com"
$headers = @{ "Authorization" = "Bearer $accessToken"; "Content-Type" = "application/json"; "Accept" = "application/json" }
$tenantId = $global:currentSession.tenantId
$request = [PSCustomObject] @{ environmentIds = @() }
$body = $request | ConvertTo-Json -Compress
}
process
{
$uri = 'https://licensing.powerplatform.microsoft.com/v2.0/tenants/{0}/BillingPolicies/getEnvironmentMap' -f $tenantId
$response = Invoke-RestMethod -Method POST `
-Uri $uri `
-Headers $headers `
-Body $body `
-ErrorAction Stop `
-Verbose:$false
return $response
}
end
{
}
}
function Get-BillingPolicy
{
[CmdletBinding()]
param
(
)
begin
{
$accessToken = Get-JwtToken -Audience "https://licensing.powerplatform.microsoft.com"
$headers = @{ "Authorization" = "Bearer $accessToken"; "Content-Type" = "application/json"; "Accept" = "application/json" }
$tenantId = $global:currentSession.tenantId
}
process
{
$uri = 'https://licensing.powerplatform.microsoft.com/v2.0/tenants/{0}/BillingPolicies' -f $tenantId
$response = Invoke-RestMethod -Method GET `
-Uri $uri `
-Headers $headers `
-ErrorAction Stop `
-Verbose:$false
$response.value
}
end
{
}
}
function Get-BillingPolicyReport
{
[CmdletBinding()]
param
(
)
begin
{
}
process
{
$environmentMaps = Get-BillingPolicyEnvironmentMap
$policies = Get-BillingPolicy
foreach( $environmentMap in $environmentMaps )
{
$policy = $policies | Where-Object -Property Id -eq $environmentMap.billingPolicyId
[PSCustomObject] @{
EnvironmentId = $environmentMap.environmentId
Id = $environmentMap.billingPolicyId
Name = $policy.name
Type = $policy.type
Status = $policy.status
Location = $policy.location
CreatedOn = $policy.createdOn
LastModifiedOn = $policy.lastModifiedOn
CreatedBy = $policy.createdBy.id
LastModifiedBy = $policy.lastModifiedBy.id
SubscriptionId = $policy.billingInstrument.subscriptionId
ResourceGroup = $policy.billingInstrument.resourceGroup
ResourceGroupId = $policy.billingInstrument.id
DataversePayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "Database" | Select-Object -ExpandProperty payAsYouGoState
PowerAutomatePayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "CloudFlowRuns" | Select-Object -ExpandProperty payAsYouGoState
PowerPagesPayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "PowerPagesAuthenticated" | Select-Object -ExpandProperty payAsYouGoState
Windows365ForAgentsPayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "W365APAYGO" | Select-Object -ExpandProperty payAsYouGoState
PowerAppsPayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "AppPass" | Select-Object -ExpandProperty payAsYouGoState
CopilotStudioPayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "MCSMessages" | Select-Object -ExpandProperty payAsYouGoState
PowerPlatformPayGoEnabled = $policy.payGoEntitlements | Where-Object -Property entitlementId -eq "ApiCalls" | Select-Object -ExpandProperty payAsYouGoState
}
}
}
end
{
}
}
function Get-EnvironmentMetadata
{
[CmdletBinding()]
param
(
)
begin
{
$accessToken = Get-JwtToken -Audience "https://api.bap.microsoft.com" -ErrorAction Stop
$headers = @{ "Authorization" = "Bearer $accessToken"; "Content-Type" = "application/json"; "Accept" = "application/json" }
}
process
{
$uri = 'https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments?api-version=2020-06-01&$expand=properties.addons,properties.capacity,properties.permissions&$top=999'
do
{
$response = Invoke-RestMethod -Method GET `
-Uri $uri `
-Headers $headers `
-ErrorAction Stop `
-Verbose:$false
$uri = $response.nextLink
foreach( $environment in $response.value )
{
[PSCustomObject] @{
Id = $environment.name
Name = $environment.properties.displayname
Location = $environment.location
CreatedDate = $environment.properties.createdTime
CreatedBy = $environment.properties.createdBy.Id
LastModifiedDate = $environment.properties.lastModifiedTime
Sku = $environment.properties.EnvironmentSku
ReleaseCycle = $environment.properties.cluster.category
IsManaged = $environment.properties.governanceConfiguration.protectionLevel -eq "Standard"
UpdateCadence = $environment.properties.updateCadence.Id
DataverseSize = $environment.properties.capacity | Where-Object -Property "capacityType" -eq "Database" | Select-Object -ExpandProperty actualConsumption
DataverseFileMB = $environment.properties.capacity | Where-Object -Property "capacityType" -eq "File" | Select-Object -ExpandProperty actualConsumption
DataverseLogMB = $environment.properties.capacity | Where-Object -Property "capacityType" -eq "Log" | Select-Object -ExpandProperty actualConsumption
VNetId = $environment.properties.enterprisePolicies.vnets | Select-Object -First 1 -ExpandProperty id
VNetPolicyName = ($environment.properties.enterprisePolicies.vnets | Select-Object -First 1 -ExpandProperty id) -split "/" | Select-Object -Last 1
VNetLinkStatus = $environment.properties.enterprisePolicies.vnets | Select-Object -First 1 -ExpandProperty linkStatus
VNetLocation = $environment.properties.enterprisePolicies.vnets | Select-Object -First 1 -ExpandProperty location
VNetPolicyId = $environment.properties.enterprisePolicies.vnets | Select-Object -First 1 -ExpandProperty policyId
VNetSystemId = $environment.properties.enterprisePolicies.vnets | Select-Object -First 1 -ExpandProperty systemId
}
}
}
while( $response.nextLink )
}
end
{
}
}
function Get-EnvironmentReport
{
[CmdletBinding()]
param
(
)
begin
{
}
process
{
$environments = Get-EnvironmentMetadata
$billingReports = Get-BillingPolicyReport
foreach( $environment in $environments )
{
$billingReport = $billingReports | Where-Object -Property "EnvironmentId" -eq $environment.Id
[PSCustomObject] @{
EnvironmentId = $environment.Id
EnvironmentName = $environment.Name
EnvironmentLocation = $environment.Location
EnvironmentCreatedDate = $environment.CreatedDate
EnvironmentCreatedBy = $environment.CreatedBy
EnvironmentLastModifiedDate = $environment.LastModifiedDate
EnvironmentSku = $environment.Sku
EnvironmentUpdateCadence = $environment.UpdateCadence
EnvironmentDataverseStorageMB = $environment.DataverseSize
EnvironmentDataverseFileMB = $environment.DataverseFileMB
EnvironmentDataverseLogMB = $environment.DataverseLogMB
EnvironmentReleaseCycle = $environment.ReleaseCycle
EnvironmentIsManaged = $environment.IsManaged
EnvironmentVNetId = $environment.VNetId
EnvironmentVNetPolicyName = $environment.VNetPolicyName
EnvironmentVNetLinkStatus = $environment.VNetLinkStatus
EnvironmentVNetLocation = $environment.VNetLocation
EnvironmentVNetPolicyId = $environment.VNetPolicyId
EnvironmentVNetSystemId = $environment.VNetSystemId
BillingPolicyId = $billingReport.Id
BillingPolicyName = $billingReport.Name
BillingPolicyType = $billingReport.Type
BillingPolicyStatus = $billingReport.Status
BillingPolicyLocation = $billingReport.Location
BillingPolicyCreatedOn = $billingReport.CreatedOn
BillingPolicyLastModifiedOn = $billingReport.LastModifiedOn
BillingPolicyCreatedBy = $billingReport.CreatedBy
BillingPolicyLastModifiedBy = $billingReport.LastModifiedBy
BillingSubscriptionId = $billingReport.SubscriptionId
BillingResourceGroup = $billingReport.ResourceGroup
BillingResourceGroupId = $billingReport.ResourceGroupId
BillingDataversePayGoEnabled = $billingReport.DataversePayGoEnabled
BillingPowerAutomatePayGoEnabled = $billingReport.PowerAutomatePayGoEnabled
BillingPowerPagesPayGoEnabled = $billingReport.PowerPagesPayGoEnabled
BillingWindows365ForAgentsPayGoEnabled = $billingReport.Windows365ForAgentsPayGoEnabled
BillingPowerAppsPayGoEnabled = $billingReport.PowerAppsPayGoEnabled
BillingCopilotStudioPayGoEnabled = $billingReport.CopilotStudioPayGoEnabled
BillingPowerPlatformPayGoEnabled = $billingReport.PowerPlatformPayGoEnabled
}
}
}
end
{
}
}
# requires power platform admin role when prompted. This is kinda a hack b/c Add-PowerAppsAccount clear existing sessions when run, so you can't load 2+ into the current session w/ that cmdlet.
$null = Get-JwtToken -Audience "https://licensing.powerplatform.microsoft.com" -ErrorAction Stop
$null = Get-JwtToken -Audience "https://api.bap.microsoft.com" -ErrorAction Stop
Get-EnvironmentReport | Export-Csv -Path "C:\_temp\PowerPlatformEnvironmentReport.csv" -NoTypeInformation
<# EXAMPLE OUTPUT
EnvironmentId : 2e20961f-f961-ef2b-b6c8-ed6b09201115
EnvironmentName : Restricted Agents
EnvironmentLocation : unitedstates
EnvironmentCreatedDate : 2025-05-12T20:37:31.1024356Z
EnvironmentCreatedBy : a8734c7e-a19b-61c6-b384-5e550ca02b9e
EnvironmentLastModifiedDate : 2025-09-02T20:58:13.9111884Z
EnvironmentSku : Sandbox
EnvironmentUpdateCadence : Frequent
EnvironmentDataverseMB : 1460.25
EnvironmentDataverseFileMB : 720.4951
EnvironmentDataverseLogMB : 0.2026167
EnvironmentVNetId : /subscriptions/aecd75f0-76ea-42b0-89d7-45bdd9977b0c/resourceGroups/powerplatform-virtualnetwork/providers/Microsoft.PowerPlatform/enterprisePolicies/powerplatform-virtualnetwork
EnvironmentVNetPolicyName : powerplatform-virtualnetwork
EnvironmentVNetLinkStatus : Linked
EnvironmentVNetLocation : unitedstates
EnvironmentVNetPolicyId : 1fd914e0-adfe-6a29-9ded-e5e6d92d7f19
EnvironmentVNetSystemId : /regions/unitedstates/providers/Microsoft.PowerPlatform/enterprisePolicies/1fd914e0-adfe-4a29-8ded-e5e6d92d7f19
BillingPolicyId : fb225338-55d8-4831-a9ca-0f74d502eeaa
BillingPolicyName : OtherDepartments
BillingPolicyType : TenantOwned
BillingPolicyStatus : Enabled
BillingPolicyLocation : unitedstates
BillingPolicyCreatedOn : 2025-08-27T17:11:37Z
BillingPolicyLastModifiedOn : 2026-04-23T13:09:07Z
BillingPolicyCreatedBy : a8734c7e-a19b-41c6-b384-4e550ca02b9e
BillingPolicyLastModifiedBy : a8734c7e-a19b-41c6-b384-4e550ca02b9e
BillingSubscriptionId : aecd75f0-76ea-42b0-89d7-45bdd9977b0c
BillingResourceGroup : paygo-catchall
BillingResourceGroupId : /subscriptions/aecd75f0-76ea-42b0-89d7-45bdd9977b0c/resourceGroups/paygo-catchall/providers/Microsoft.PowerPlatform/accounts/OtherDepartments
BillingDataversePayGoEnabled : True
BillingPowerAutomatePayGoEnabled : True
BillingPowerPagesPayGoEnabled : True
BillingWindows365ForAgentsPayGoEnabled : False
BillingPowerAppsPayGoEnabled : True
BillingCopilotStudioPayGoEnabled : False
BillingPowerPlatformPayGoEnabled : True
#>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment