Tutorial: Create a daily capacity report (preview)
[This article is pre-release documentation and is subject to change.]
The Power Platform API can be used to extract various details and metadata from your Microsoft Power Platform environments with or without a Microsoft Dataverse database. The API is used internally by various clients available today such as PowerShell.
In this tutorial, you learn how to:
- Create a Power Automate or Logic Apps workflow (Azure) or PowerShell script that authenticates with the Power Platform API.
- Call the List Environments endpoint to retrieve your Microsoft Power Platform environment details.
- Iterate through the capacity object to retrieve the actual consumption.
- Save the consumption data into a table for display.
As an example of this scenario, a customer is looking to get a handle on their capacity consumption so that they can better understand the allocation of their total tenant capacity by department. This helps the customer to perform some internal cost accounting functions and charge backs based on how much each department is consuming of the total available capacity. This customer is using the environment Description to call out the department that owns each environment.
Important
The Power Platform API is in preview. The host name and data contracts are subject to change by the time the endpoints become generally available.
Connect and variable setup
Use the following details on getting connected to the Power Platform programmatically. You can choose between an Azure experience or PowerShell scripts.
Create the workflow and set up the variables
To start off, in this tutorial we use a Logic Apps workflow. A Power Automate flow is also acceptable, and any other orchestration engine that your company prefers to use for automation. All of the calls to retrieve the data use RESTful APIs so any tooling that supports REST works with this tutorial.
Visit the Azure portal, and then create a new logic app and give it a name:
After that finishes provisioning, edit the workflow using the Designer and set up a Recurrence trigger to run daily:
Next, we need to initialize five variables:
- SPN-Id – This is your service principal ClientID. It's used later to perform the authentication in a service principal context. If you're using username/password context, you can skip this variable.
- DBCapacity – This is a Float variable for the consumed database capacity in megabytes.
- FileCapacity – This is a Float variable for the consumed file capacity in megabytes.
- LogCapacity – This is a Float variable for the consumed log capacity in megabytes.
- SimplifiedEnvironmentArray-Init – This is an array variable that we populate with a few environment properties. This drastically simplifies the final HTML table report output.
Next, we authenticate with Microsoft Entra and retrieve a token for calling the Power Platform API. If you haven’t completed your Microsoft Entra setup, see Authentication - legacy.
In this tutorial, we're using a key vault to store our service principal secret value. In this way, an IT administrator can make this value securely available for your workflow. This is then populated in the POST call to Microsoft Entra to retrieve the token.
We then parse the Microsoft Entra token response into a typed object using this JSON schema in the 'Parse JSON' action:
{
"properties": {
"access_token": {
"type": "string"
},
"expires_in": {
"type": "integer"
},
"ext_expires_in": {
"type": "integer"
},
"token_type": {
"type": "string"
}
},
"type": "object"
}
Fetch environments
In this section, we fetch the environment list that you administer. This can be done via API and PowerShell.
Call the List Environments endpoint
Now is the time to call the Power Platform API. Use the List Environments endpoint to retrieve all of our environments and their metadata, specifically with the $expand parameter for capacity. This also uses the Authorization header with the Bearer Token we received in the previous section from Microsoft Entra ID. If you used username/password context, you can also enter that Bearer Token at this step as well.
We then parse the Power Platform API response into a typed object using this JSON schema with the 'Parse JSON' action:
{
"properties": {
"value": {
"items": {
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"location": {
"type": "string"
},
"name": {
"type": "string"
},
"properties": {
"properties": {
"addons": {
"type": "array"
},
"azureRegion": {
"type": "string"
},
"capacity": {
"items": {
"properties": {
"actualConsumption": {
"type": "number"
},
"capacityType": {
"type": "string"
},
"capacityUnit": {
"type": "string"
},
"ratedConsumption": {
"type": "number"
},
"updatedOn": {
"type": "string"
}
},
"required": [
"capacityType",
"actualConsumption",
"ratedConsumption",
"capacityUnit",
"updatedOn"
],
"type": "object"
},
"type": "array"
},
"clientUris": {
"properties": {
"admin": {
"type": "string"
},
"maker": {
"type": "string"
}
},
"type": "object"
},
"cluster": {
"properties": {
"category": {
"type": "string"
},
"number": {
"type": "string"
}
},
"type": "object"
},
"connectedGroups": {
"type": "array"
},
"createdBy": {
"properties": {
"displayName": {
"type": "string"
},
"id": {
"type": "string"
},
"type": {
"type": "string"
}
},
"type": "object"
},
"createdTime": {
"type": "string"
},
"creationType": {
"type": "string"
},
"databaseType": {
"type": "string"
},
"displayName": {
"type": "string"
},
"environmentSku": {
"type": "string"
},
"isDefault": {
"type": "boolean"
},
"linkedEnvironmentMetadata": {
"properties": {
"backgroundOperationsState": {
"type": "string"
},
"baseLanguage": {
"type": "number"
},
"createdTime": {
"type": "string"
},
"domainName": {
"type": "string"
},
"friendlyName": {
"type": "string"
},
"instanceApiUrl": {
"type": "string"
},
"instanceState": {
"type": "string"
},
"instanceUrl": {
"type": "string"
},
"platformSku": {
"type": "string"
},
"resourceId": {
"type": "string"
},
"scaleGroup": {
"type": "string"
},
"uniqueName": {
"type": "string"
},
"version": {
"type": "string"
}
},
"type": "object"
},
"protectionStatus": {
"properties": {
"keyManagedBy": {
"type": "string"
}
},
"type": "object"
},
"provisioningState": {
"type": "string"
},
"retentionDetails": {
"properties": {
"backupsAvailableFromDateTime": {
"type": "string"
},
"retentionPeriod": {
"type": "string"
}
},
"type": "object"
},
"retentionPeriod": {
"type": "string"
},
"runtimeEndpoints": {
"properties": {
"microsoft.ApiManagement": {
"type": "string"
},
"microsoft.BusinessAppPlatform": {
"type": "string"
},
"microsoft.CommonDataModel": {
"type": "string"
},
"microsoft.Flow": {
"type": "string"
},
"microsoft.PowerApps": {
"type": "string"
},
"microsoft.PowerAppsAdvisor": {
"type": "string"
}
},
"type": "object"
},
"states": {
"properties": {
"management": {
"properties": {
"id": {
"type": "string"
}
},
"type": "object"
},
"runtime": {
"properties": {
"id": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
},
"updateCadence": {
"properties": {
"id": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
},
"type": {
"type": "string"
}
},
"required": [
"id",
"type",
"location",
"name",
"properties"
],
"type": "object"
},
"type": "array"
}
},
"type": "object"
}
Iterate through the Capacity object
This is the most complex part of the tutorial. Here we use a loop inside of a loop to iterate each environment in the List Environment response, and each environment has an array of capacity details that we iterate as well. This lets us capture the necessary information for each environment row in our capacity report table.
For-each and parsing
Let’s take this step by step. First, we use a For Each control using the ‘value’ of the Parse-List-Response output:
Then we parse this single environment into a typed object using this JSON schema:
{
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "string"
},
"location": {
"type": "string"
},
"name": {
"type": "string"
},
"properties": {
"properties": {
"addons": {
"type": "array"
},
"azureRegion": {
"type": "string"
},
"capacity": {
"items": {
"properties": {
"actualConsumption": {
"type": "number"
},
"capacityType": {
"type": "string"
},
"capacityUnit": {
"type": "string"
},
"ratedConsumption": {
"type": "number"
},
"updatedOn": {
"type": "string"
}
},
"required": [
"capacityType",
"actualConsumption",
"ratedConsumption",
"capacityUnit",
"updatedOn"
],
"type": "object"
},
"type": "array"
},
"clientUris": {
"properties": {
"admin": {
"type": "string"
},
"maker": {
"type": "string"
}
},
"type": "object"
},
"cluster": {
"properties": {
"number": {
"type": "string"
}
},
"type": "object"
},
"connectedGroups": {
"type": "array"
},
"createdBy": {
"properties": {
"displayName": {
"type": "string"
},
"id": {
"type": "string"
},
"type": {
"type": "string"
}
},
"type": "object"
},
"createdTime": {
"type": "string"
},
"creationType": {
"type": "string"
},
"databaseType": {
"type": "string"
},
"displayName": {
"type": "string"
},
"environmentSku": {
"type": "string"
},
"isDefault": {
"type": "boolean"
},
"linkedEnvironmentMetadata": {
"properties": {
"backgroundOperationsState": {
"type": "string"
},
"baseLanguage": {
"type": "integer"
},
"createdTime": {
"type": "string"
},
"domainName": {
"type": "string"
},
"friendlyName": {
"type": "string"
},
"instanceApiUrl": {
"type": "string"
},
"instanceState": {
"type": "string"
},
"instanceUrl": {
"type": "string"
},
"resourceId": {
"type": "string"
},
"scaleGroup": {
"type": "string"
},
"uniqueName": {
"type": "string"
},
"version": {
"type": "string"
}
},
"type": "object"
},
"protectionStatus": {
"properties": {
"keyManagedBy": {
"type": "string"
}
},
"type": "object"
},
"provisioningState": {
"type": "string"
},
"retentionDetails": {
"properties": {
"backupsAvailableFromDateTime": {
"type": "string"
},
"retentionPeriod": {
"type": "string"
}
},
"type": "object"
},
"retentionPeriod": {
"type": "string"
},
"runtimeEndpoints": {
"properties": {
"microsoft.ApiManagement": {
"type": "string"
},
"microsoft.BusinessAppPlatform": {
"type": "string"
},
"microsoft.CommonDataModel": {
"type": "string"
},
"microsoft.Flow": {
"type": "string"
},
"microsoft.PowerApps": {
"type": "string"
},
"microsoft.PowerAppsAdvisor": {
"type": "string"
}
},
"type": "object"
},
"states": {
"properties": {
"management": {
"properties": {
"id": {
"type": "string"
}
},
"type": "object"
},
"runtime": {
"properties": {
"id": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
},
"updateCadence": {
"properties": {
"id": {
"type": "string"
}
},
"type": "object"
}
},
"type": "object"
},
"type": {
"type": "string"
}
},
"type": "object"
}
Next, we use another For Each control using the ‘capacity’ of the Parse-CurrentItem output. Then we parse this into a typed object using this JSON schema:
Now we can use the Switch control on the CapacityType property from the Parse-Capacity output. This is either the value of ‘Database’, ‘File’, or ‘Log’. Under each switch case, capture the related ‘actualConsumption’ property into the related variable. In the following case, you see we're capturing Database capacity:
As the last step in the ‘For each environment’ loop, we now can capture the environment details for this row in the report. Using the Append to array variable control, use the following JSON schema:
{
"properties": {
"actualConsumption": {
"type": "number"
},
"capacityType": {
"type": "string"
},
"capacityUnit": {
"type": "string"
},
"ratedConsumption": {
"type": "number"
},
"updatedOn": {
"type": "string"
}
},
"type": "object"
}
Build report table
Congratulations, you’ve now made it to the easy part! Now that we have our fully populated and simplified environment capacity array, we can display it in tabular format.
Use the HTML Table connector
Running the logic app, we can now see the output of the HTML table report:
The report could be optionally emailed to stakeholders in this example for Cost Accounting purposes, or the data could be saved into a database for further analysis and historical trending.