
Managing Power Apps and Power Automate in an enterprise tenant with thousands or even tens of thousands of users can be a bit of a challenge. Especially with the current licensing model with premium connectors requiring additional licenses that require us to analyse how premium connectors are used across our tenant to stay compliant.
The Microsoft Power Platform Center of Excellence Starter Kit will get you parts of the way but also often fall short, simply not gathering enough information.
Recently I wanted a list of all the apps and flows in a specific environment that use any of the premium connectors. I also want to include information about all owners and users that are able to edit these apps and flows and not only the maker.
Below you will find a PowerShell script that will export this information to a number of different CSV files that then can be parsed.
The output will be two files for Power Apps apps and two files for Power Automate flows. One file with all the apps/flows and their premium connectors and another one with all the owners and users that can manage these apps and flows together with all the apps and flows using premium connectors.
Import-Module -Name Microsoft.PowerApps.Administration.PowerShell Import-Module -Name Microsoft.PowerApps.PowerShell Import-Module AzureADPreview $folderPath = 'C:\Temp\Exports' $environment = '[ID]' Add-PowerAppsAccount Connect-AzureAD ################################################### # Get Premium Apps $apps = @(Get-AdminPowerApp -EnvironmentName $environment) Write-host ('Number of apps: ' + $apps.Count) $premiumApps = @() $premiumAppsOwners = @() $totalApps = $apps.Count foreach ($app in $apps) { Write-host ('App: ' + $app.AppName ) $premiumConnectors = '' $appOwners = '' # Go through the connections and look for premium connectors. foreach($conRef in $app.Internal.properties.connectionReferences) { foreach($connection in $conRef) { foreach ($connId in ($connection | Get-Member -MemberType NoteProperty).Name) { $connDetails = $($connection.$connId) if ($connDetails.apiTier -eq 'Premium') { $premiumConnectors += (&{if ($premiumConnectors) { ', ' }}) + $connDetails.displayName } } } } # Get all the users who can edit the power app. if ($premiumConnectors.length -gt 0) { $roleAssignment = Get-AdminPowerAppRoleAssignment -EnvironmentName $app.EnvironmentName -AppName $app.AppName $owners = $roleAssignment | Where-Object { $_.RoleType -eq 'CanEdit' -or $_.RoleType -eq 'Owner' } foreach ($asgmt in $owners) { if ($asgmt.PrincipalEmail.length -gt 0) { $appOwners += (&{if($appOwners) { ', ' }}) + $asgmt.PrincipalEmail $appOwner = $premiumAppsOwners | Where-Object { $_.Mail -eq $asgmt.PrincipalEmail } if ($appOwner) { $appOwner.Apps += ', ' + $app.DisplayName + '(' + $premiumConnectors + ')' } else { $appOwnerRow = @{ Mail = $asgmt.PrincipalEmail Apps = $app.DisplayName + '(' + $premiumConnectors + ')' } $premiumAppsOwners += $(new-object psobject -Property $appOwnerRow) } } } $row = @{ ResourceType = 'PowerApp' DisplayName = $app.displayName Name = $app.appName EnvironmentName = $app.environmentName CreatedByObjectId = $app.owner.id CreatedByEmail = $app.owner.email Owners = $appOwners PremiumConnectors = $premiumConnectors } $premiumApps += $(new-object psobject -Property $row) Write-host 'Premium connectors found.' } } $premiumApps | Export-Csv -Path ($folderPath + '\PremiumApps2.csv') -Delimiter ';' -NoTypeInformation $premiumAppsOwners | Export-Csv -Path ($folderPath + '\PremiumAppOwners2.csv') -Delimiter ';' -NoTypeInformation ################################################### # Get Premium Flows $flows = @(Get-AdminFlow -EnvironmentName $environment) Write-host ('Number of flows: ' + $flows.Count) $premiumFlows = @() $premiumFlowOwners = @() $totalFlows = $flows.Count foreach ($flow in $flows) { Write-host ('Flow: ' + $flow.DisplayName ) # Load the Flow details. Without this we don't get the proper and detailed connection details. $flowDetails = $flow | Get-AdminFlow $premiumConnectors = '' $flowOwners = '' # Look for premium connectors. foreach($conRef in $flowDetails.Internal.properties.connectionReferences) { foreach($connection in $conRef) { foreach ($connId in ($connection | Get-Member -MemberType NoteProperty).Name) { $connDetails = $($connection.$connId) $connector = $connectors | Where-Object { $_.DisplayName -eq $connDetails.displayName } if ($connDetails.tier -eq 'Premium') { $premiumConnectors += (&{if ($premiumConnectors) { ', ' }}) + $connDetails.displayName } } } } # Get all the users who can edit the flow. if ($premiumConnectors.Length -gt 0) { $flowOwnerRole = @(Get-AdminFlowOwnerRole -FlowName $flow.FlowName -EnvironmentName $flow.EnvironmentName) $owners = $flowOwnerRole | Where-Object { $_.RoleType -eq 'CanEdit' -or $_.RoleType -eq 'Owner' } foreach ($role in $owners) { $user = Get-AzureADUser -ObjectId $role.PrincipalObjectId if ($user.Mail.length -gt 0) { $flowOwners += (&{if($flowOwners) { ', ' }}) + $user.Mail $flowOwner = $premiumFlowOwners | Where-Object { $_.Mail -eq $user.Mail } if ($flowOwner) { $flowOwner.Flows += ', ' + $flow.DisplayName + '(' + $premiumConnectors + ')' } else { $flowOwnerRow = @{ Mail = $user.Mail Flows = $flow.DisplayName + '(' + $premiumConnectors + ')' } $premiumFlowOwners += $(new-object psobject -Property $flowOwnerRow) } } } $row = @{ ResourceType = 'Flow' DisplayName = $flow.DisplayName Id = $flow.FlowName EnvironmentName = $flow.environmentName CreatedByObjectId = $flow.CreatedBy.objectId Owners = $flowOwners PremiumConnectors = $premiumConnectors } $premiumFlows += $(new-object psobject -Property $row) Write-host 'Premium connectors found.' } } $premiumFlows | Export-Csv -Path ($folderPath + '\PremiumFlows2.csv') -Delimiter ';' -NoTypeInformation $premiumFlowOwners | Export-Csv -Path ($folderPath + '\PremiumFlowOwners2.csv') -Delimiter ';' -NoTypeInformation
Please note that the script looks for the tier information (premium or standard) stored in the connection references in the save app or flow. Analysing this tier information in the saved apps or flows will tell you if these connections were premium or standard at the time the app or flow was saved. It’s not that often that Microsoft change the tier of an existing connector, but it happens. If you have a lot of old apps and flows you may want to consider looking for updated tier information in a current list with all the connectors instead of the information stored in each app or flow.
Got a lot of inspiration from Denise Moran and her excellent article PowerShell scripts to discover and manage specific features in the Power Platform.