Tuesday, March 10, 2026

Finding & Reassigning Abandoned Flows in Power Platform

Power Platform Administration

Finding & Reassigning Abandoned Flows

A complete, beginner-friendly guide using PowerShell

March 2025    Power Automate    PowerShell    Microsoft Graph

Introduction

If you manage a Microsoft Power Platform environment — even a small one — you have almost certainly run into this situation: flows that nobody owns, flows sitting in a broken state for months, flows owned by employees who have long since left the company. These are what we call abandoned flows.

 

This blog post walks you through exactly what abandoned flows are, why they are a problem, how to find them using PowerShell, and how to take ownership of them so you can fix or clean them up. No prior PowerShell experience is required — every step is explained in plain English.

 

What Are Abandoned Flows?

A Power Automate flow is a set of automated steps that runs on a trigger (like a new email, a form submission, or a schedule). Flows are owned by users in your organisation. An abandoned flow is any flow that has effectively become ownerless or unmanaged. This typically happens in one of four ways:

 

Category

Description

Orphaned

The original owner's account was deleted or disabled in Entra ID (Azure AD). The flow still exists but has no active owner.

Suspended

Power Platform automatically suspends a flow when its connections break (e.g. a password change, licence removal, or connector expiry).

Stopped

Someone turned the flow off and it has been sitting idle with no modification for a long time.

Stale

The flow is technically on, but has not been modified or checked in 90+ days and may be running on outdated logic.

 

💡  Why does this matter?  Abandoned flows can quietly fail, consume API quota, hold licences, or contain sensitive data with no one watching over them. In an audit or compliance review, they are a red flag.

 

Before You Start — Prerequisites

You will need the following before running any of the scripts in this guide:

 

       Power Platform Admin role or Global Admin in your Microsoft 365 tenant

       PowerShell 5.1 or PowerShell 7+ installed on your machine

       Internet access to reach the Power Platform admin APIs

 

Install the required PowerShell modules by running these commands once:

 

# Power Platform Admin module

Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force -AllowClobber

 

# Microsoft Graph (for looking up Entra ID users)

Install-Module Microsoft.Graph -Scope CurrentUser -Force

 

⚠️  You only need to install these modules once. After that, you can just run the scripts directly.

 

Step 1 — Connect to Power Platform

Before the scripts can talk to your tenant, you must authenticate. Run the following:

 

# Sign in to Power Platform Admin

Add-PowerAppsAccount

 

# Sign in to Microsoft Graph (for user lookups)

Connect-MgGraph -Scopes 'User.Read.All'

 

A browser window will open asking you to sign in with your admin account. Once signed in, you are ready to proceed.

 

Step 2 — Find All Abandoned Flows

The script below loops through every environment in your tenant, collects all flows, and flags them as abandoned if they are suspended, stopped, or have not been modified in 90 days.

 

# How many days without modification counts as stale?

$staleDays = 90

$staleCutoff = (Get-Date).AddDays(-$staleDays)

 

# Collect all flows across all environments

$environments = Get-AdminPowerAppEnvironment

$abandonedFlows = @()

 

foreach ($env in $environments) {

    Write-Host "Scanning: $($env.DisplayName)" -ForegroundColor Cyan

    $flows = Get-AdminFlow -EnvironmentName $env.EnvironmentName

 

    foreach ($flow in $flows) {

        $state   = $flow.Internal.properties.state

        $lastMod = $flow.LastModifiedTime

 

        if ($state -in @("Suspended","Stopped") -or $lastMod -lt $staleCutoff) {

            $abandonedFlows += [PSCustomObject]@{

                DisplayName = $flow.DisplayName

                FlowName    = $flow.FlowName

                Environment = $env.EnvironmentName

                EnvDisplay  = $env.DisplayName

                State       = $state

                LastMod     = $lastMod

                Owner       = $flow.CreatedBy.userPrincipalName

            }

        }

    }

}

 

Write-Host "Found $($abandonedFlows.Count) abandoned flows" -ForegroundColor Yellow

$abandonedFlows | Format-Table DisplayName, EnvDisplay, State, Owner -AutoSize

 

At this point, you will see a table printed in your PowerShell window listing every abandoned flow. Take a moment to review it before moving on.

 

Bonus: Find Flows Owned by Deleted Users

If you also want to catch flows whose owner account no longer exists in Entra ID (for example, ex-employees), add this extra check:

 

# Get all active user UPNs from Entra ID

$activeUsers = Get-MgUser -All | Select-Object -ExpandProperty UserPrincipalName

 

# Filter flows where owner is not in active user list

$orphanedFlows = $abandonedFlows | Where-Object {

    $_.Owner -notin $activeUsers -and $_.Owner -ne $null

}

 

Write-Host "Orphaned (owner deleted): $($orphanedFlows.Count)"

$orphanedFlows | Format-Table DisplayName, Owner, EnvDisplay -AutoSize

 

Step 3 — Assign Abandoned Flows to Yourself

Now that you have a list, you can assign yourself as a co-owner (CanEdit) of each abandoned flow. This gives you full control to fix, update, or delete them.

 

📝  Note: Power Platform does not support changing the original creator of a flow. What you can do is add yourself as a co-owner with CanEdit permission, which gives you the same level of control as the original owner.

 

First, get your own Object ID. This is a unique identifier for your account in Entra ID. The simplest way is:

 

# Option A: Get your Object ID from the Power Platform session (no extra module needed)

$myObjectId = (Get-PowerAppsAccount).UserId

Write-Host "Your Object ID: $myObjectId"

 

# Option B: Look it up via Microsoft Graph

$myUPN      = "your.email@company.com"

$myObjectId = (Get-MgUser -UserId $myUPN).Id

 

Now run the reassignment loop. Each flow is processed in its own background job with a 30-second timeout to prevent the script from hanging on a single slow API call:

 

$success = @()

$failed  = @()

$i       = 0

 

foreach ($flow in $abandonedFlows) {

    $i++

    Write-Host "[$i/$($abandonedFlows.Count)] $($flow.DisplayName)..." -NoNewline

 

    try {

        $job = Start-Job -ScriptBlock {

            param($envName, $flowName, $oid)

            Add-PowerAppsAccount

            Set-AdminFlowOwnerRole `

                -EnvironmentName $envName `

                -FlowName        $flowName `

                -RoleName        CanEdit `

                -PrincipalType   User `

                -PrincipalObjectId $oid

        } -ArgumentList $flow.Environment, $flow.FlowName, $myObjectId

 

        $done = Wait-Job $job -Timeout 30

        if ($done) {

            Receive-Job $job

            Write-Host " OK" -ForegroundColor Green

            $success += $flow

        } else {

            Stop-Job $job

            Write-Host " TIMEOUT" -ForegroundColor Yellow

            $failed += $flow

        }

        Remove-Job $job -Force

    }

    catch {

        Write-Host " ERROR: $_" -ForegroundColor Red

        $failed += $flow

    }

 

    # Pause every 10 flows to avoid API throttling

    if ($i % 10 -eq 0) { Start-Sleep -Seconds 5 }

}

 

Write-Host ""

Write-Host "=== Done ===" -ForegroundColor Cyan

Write-Host "Assigned : $($success.Count)" -ForegroundColor Green

Write-Host "Failed   : $($failed.Count)"  -ForegroundColor Red

 

Step 4 — Export a Report

It is good practice to save a record of what was changed. Export the results to CSV files so you have an audit trail:

 

$date = Get-Date -Format "yyyyMMdd"

 

# All abandoned flows found

$abandonedFlows | Export-Csv "AbandonedFlows_$date.csv"     -NoTypeInformation

 

# Flows successfully reassigned

$success        | Export-Csv "Reassigned_$date.csv"          -NoTypeInformation

 

# Flows that failed or timed out

$failed         | Export-Csv "Failed_$date.csv"              -NoTypeInformation

 

Write-Host "Reports saved to current directory."

 

Troubleshooting Common Issues

 

Category

Description

Script hangs for 10+ min

The cmdlet is stuck on a single API call. Use the Start-Job / Wait-Job pattern (Step 3) with a 30-second timeout to prevent this.

Get-AzureADUser not found

The AzureAD module is deprecated. Use Get-MgUser from the Microsoft.Graph module instead.

Access denied errors

Your account needs Power Platform Admin or Global Admin. Check your role in the Microsoft 365 Admin Center.

Set-AdminFlowOwnerRole no output

This is normal — the cmdlet returns nothing on success. Check $success count after the loop.

Throttling / 429 errors

Add Start-Sleep -Seconds 5 every 10 flows (already included in Step 3 script).

 

Best Practices — Keep Your Environment Clean

Now that you know how to find and claim abandoned flows, here are some habits to prevent the problem from building up again:

 

       Run this script monthly as part of your regular admin routine

       Set up a DLP (Data Loss Prevention) policy to limit which connectors flows can use

       Before offboarding a user, reassign their flows to a service account or a team owner

       Use solutions to package flows, which makes ownership and lifecycle management easier

       Enable environment-level auditing so you get alerts when flows enter a suspended state

 

Quick Reference Summary

 

Category

Description

Step 1

Install modules: Microsoft.PowerApps.Administration.PowerShell and Microsoft.Graph

Step 2

Connect: Add-PowerAppsAccount and Connect-MgGraph

Step 3

Find abandoned flows: loop environments, filter by state and last modified date

Step 4

Get your Object ID: (Get-PowerAppsAccount).UserId

Step 5

Reassign with timeout: Set-AdminFlowOwnerRole inside Start-Job / Wait-Job

Step 6

Export results to CSV for audit trail

 

 

Conclusion

Abandoned flows are a silent problem in most Power Platform tenants — they go unnoticed until something breaks or an auditor asks questions. With the scripts and steps in this guide, you can find every abandoned flow in your environment, understand why it was abandoned, and take ownership of it in minutes.

 

The entire process uses built-in Microsoft modules, requires no third-party tools, and can be scheduled to run automatically. Start with a single test flow, confirm it works, then scale up to your full environment.

 

Happy automating!

 -----------------------------------------------------------------------------------------------------------

# Install module if needed

Install-Module -Name Microsoft.PowerApps.Administration.PowerShell

 

# Connect

Add-PowerAppsAccount

 

# Get the flow (you need Environment Name + Flow ID)

Get-AdminFlow -EnvironmentName "Default-<tenantid>" | Where-Object { $_.DisplayName -like "*FlowName*" }

 

# Assign

Set-AdminFlowOwnerRole `

    -EnvironmentName $flow.Environment `

    -FlowName $flow.FlowName `

    -RoleName CanEdit `

    -PrincipalType User `

    -PrincipalObjectId $newOwnerOID   

 -----------------------------------------------------------------------------------------------------------


Wednesday, February 18, 2026

Create SharePoint Folder Structure in Destination (Only If Not Exists)

Why This Script Is Safe

  • You can run it multiple times

  • It will not create duplicate folders

  • It will only create missing folders

  • Safe for automation

############################################################

# CONFIGURATION

############################################################

 

# Azure AD App Registration details

$ApplicationClientId     = "Client id"

$ApplicationClientSecret = "Client Secret"

$TenantId                = "Tenant ID"

 

# SharePoint Sites

$SourceSiteUrl      = "https://sourcesite.com/sites/site1"

$DestinationSiteUrl = "https://destination.com/sites/site2"

 

############################################################

# SOURCE FOLDER URLS (Full URLs from Source Site)

############################################################

 

$SourceFolderUrls = @(

    "https://sourcesite.com/Shared Documents/folder3/subfolder3.1",

    "https://sourcesite.com/Shared Documents/folder4/subfolder4.1"

)

 

############################################################

# CONNECT TO DESTINATION SITE (Only once)

############################################################

 

Connect-PnPOnline `

    -Url $DestinationSiteUrl `

    -ClientId $ApplicationClientId `

    -ClientSecret $ApplicationClientSecret `

    -Tenant $TenantId `

    -WarningAction Ignore

 

############################################################

# PROCESS EACH FOLDER

############################################################

 

foreach ($FullFolderUrl in $SourceFolderUrls) {

    Write-Host "Processing: $FullFolderUrl" -ForegroundColor Cyan

 

    # Convert URL to URI object

    $Uri = [System.Uri]$FullFolderUrl

 

    # Get server-relative path

    # Example: /Shared Documents/folder3/subfolder3.1

    $ServerRelativePath = $Uri.AbsolutePath

 

    # Remove site name to get site-relative path

    # Example result: Shared Documents/folder3/subfolder3.1

    $SiteRelativePath = $ServerRelativePath.Replace(

        "/" + $Uri.AbsolutePath.Split('/')[1] + "/" + $Uri.AbsolutePath.Split('/')[2] + "/",

        ""

    )

 

    ############################################################

    # IMPORTANT:

    # This command CREATES the folder ONLY IF IT DOES NOT EXIST

    # If folder already exists → nothing happens

    # If folder does not exist → it gets created

############################################################


    Resolve-PnPFolder -SiteRelativePath $SiteRelativePath

    Write-Host "Folder ensured (created if missing): $SiteRelativePath" -ForegroundColor Green

}

 

############################################################

# COMPLETED

############################################################

 

Write-Host "Folder structure creation completed successfully." -ForegroundColor Yellow

 




Featured Post

Finding & Reassigning Abandoned Flows in Power Platform

Power Platform Administration Finding & Reassigning Abandoned Flows A complete, beginner-friendly guide using PowerShell March 2...

Popular posts