
Highlight
If you read my previous post on logic app costs and effect of scale, here is another tip for you
Which is, how to find underutilized logic apps to save a lot of money for your org!
Intro
Every single logic app that is not used in a private network environment will cos you around 25-32 USD per month, so the more you find the better.
Why? I’ve covered this in the article about the effect of scale. But in short, it’s about the cost, or more, about reduction of it. With private network environment each underutilized logic app will cost you, hence finding out underutilized logic apps will save you a ton of money.
- Reference article Watch out for the ‘effect of scale’
Myself, I’m a simple person, a simple problem must have a simple solution. So I’ve wrote this script. It run for 30 minutes (API is slow for some reason), and I’ve found 50,000 USD yearly savings for my organization. Big win in 30 minutes, don’t you think?
It’s open source so feel free to use it :)
# Ensure you are logged into Azure
# Connect-AzAccount
# Install Az.ResourceGraph module if not installed
if (-not (Get-Module -ListAvailable -Name Az.ResourceGraph)) {
Install-Module -Name Az.ResourceGraph -Scope CurrentUser -Force
}
# Query Azure Resource Graph to get all App Service resource IDs
$query = @"
resourcecontainers
| where ['type'] == 'microsoft.resources/subscriptions'
| where properties.managementGroupAncestorsChain[0].displayName startswith "Tenant Root Group"
or properties.managementGroupAncestorsChain[0].displayName startswith "B"
or properties.managementGroupAncestorsChain[0].displayName startswith "C"
or properties.managementGroupAncestorsChain[0].displayName startswith "D"
| project subscriptionId
| join kind=inner (
resources
| where type =~ 'microsoft.web/sites'
| where kind == 'functionapp,workflowapp'
) on subscriptionId
| project id
"@
# Run the query across all subscriptions
$appServices = Search-AzGraph -Query $query -First 1000
# Output the list of resource IDs
$appServices.id
$laEmptyCount = 0
foreach( $id in $appServices.id ) {
$workflows = Invoke-AzRestMethod -Uri "https://management.azure.com/$id/workflows?api-version=2024-04-01"
$parsedResponse = $workflows.Content | ConvertFrom-Json
if($parsedResponse.value.Count -eq 0) {
$laEmptyCount = $laEmptyCount + 1
$laEmptyCount
Write-Host "Unused LA: $id"
}
}
Write-Host "Unused logic apps count: $laEmptyCount"
Just update this part with your management groups, or remove this where to search all azure subscriptions you have access to
| where properties.managementGroupAncestorsChain[0].displayName startswith "A"
or properties.managementGroupAncestorsChain[0].displayName startswith "B"
or properties.managementGroupAncestorsChain[0].displayName startswith "C"
or properties.managementGroupAncestorsChain[0].displayName startswith "D"
Either
- Use “Tenant Root Group” in the where statement to include all subscriptions under root management group or,
- Just remove entire where statement altogether
Here is the code
Executing the code
If you run the code in https://shell.azure.com you should see something like this

Output
PS /home/adam> # Install Az.ResourceGraph module if not installed
PS /home/adam> if (-not (Get-Module -ListAvailable -Name Az.ResourceGraph)) {
>> Install-Module -Name Az.ResourceGraph -Scope CurrentUser -Force
>> }
PS /home/adam>
PS /home/adam> # Query Azure Resource Graph to get all App Service resource IDs
PS /home/adam> $query = @"
>> resourcecontainers
>> | where ['type'] == 'microsoft.resources/subscriptions'
>> | where properties.managementGroupAncestorsChain[0].displayName startswith "Tenant Root Group"
>> or properties.managementGroupAncestorsChain[0].displayName startswith "B"
>> or properties.managementGroupAncestorsChain[0].displayName startswith "C"
>> or properties.managementGroupAncestorsChain[0].displayName startswith "D"
>> | project subscriptionId
>> | join kind=inner (
>> resources
>> | where type =~ 'microsoft.web/sites'
>> | where kind == 'functionapp,workflowapp'
>> ) on subscriptionId
>> | project id
>> "@
PS /home/adam>
PS /home/adam> # Run the query across all subscriptions
PS /home/adam> $appServices = Search-AzGraph -Query $query -First 1000
PS /home/adam>
PS /home/adam> # Output the list of resource IDs
PS /home/adam> $appServices.id
/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/logic-apps-standard-cicd-rg/providers/Microsoft.Web/sites/logicappscicd
/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/logic-apps-standard-cicd-rg/providers/Microsoft.Web/sites/logicappscicd-prod
/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/sb-rg/providers/Microsoft.Web/sites/amdemosb
PS /home/adam>
PS /home/adam> $laEmptyCount = 0
PS /home/adam> foreach( $id in $appServices.id ) {
>> $workflows = Invoke-AzRestMethod -Uri "https://management.azure.com/$id/workflows?api-version=2024-04-01"
>> $parsedResponse = $workflows.Content | ConvertFrom-Json
>> if($parsedResponse.value.Count -eq 0) {
>> $laEmptyCount = $laEmptyCount + 1
>> $laEmptyCount
>> Write-Host "Unused LA: $id"
>> }
>> }
Here is the key info
Logic App Standard SKU found in your selected query
PS /home/adam> # Output the list of resource IDs
PS /home/adam> $appServices.id
/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/logic-apps-standard-cicd-rg/providers/Microsoft.Web/sites/logicappscicd
/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/logic-apps-standard-cicd-rg/providers/Microsoft.Web/sites/logicappscicd-prod
/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/sb-rg/providers/Microsoft.Web/sites/amdemosb
And if you find a logic app which will be ununsed, then it will print something like this
Unused LA: $/subscriptions/f73706f8-c55b-42b7-9d31-6fc8e0d24146/resourceGroups/sb-rg/providers/Microsoft.Web/sites/amdemosb
And at the end the amount of unused logic apps
Unused logic apps count: 1
Next Actions
Here are some recommendations from me on what you can check out next if you want to learn more
Source Code