Effortlessly Trigger a Flow from a Power App: A Simple Step-by-Step Example

In this post, I want to show how easy it is to call a Flow from a Power App. The goal of the Power App is to pass values to the Flow, have it add them together, and return a result.

Starting from the Power Apps portal
click Create –> Blank app, Black canvas app, name the app, for the format option, select tablet, then click Create button.

Power App overview:

Field TypeField NameOption
Text InputTextInputOneFormat: Number
Text InputTextInputTwoFormat: Number
LabelLabelNumberOne
LabelLabelNumberTwo
LabelLabelTotal
LabelLabelMathResult
ButtonButtonCalc

Flow overview:
The Flow can be created directly in the Power App designer or the Power Platform portal. For this example, I’m going to use the portal.

From https://make.powerapps.com,
Click on New flow and select Automated cloud flow

Click the Skip button at the bottom of the window (this will make sense in a min.)

With the Flow designer open, click PowerApps or search for it, then click on PowerApps (V2)

In this step, add two number inputs to the action

I named my number inputs as follow: inputNumberOne and inputNumberTwo

The Flow will respond to the app using the Repost to a PowerApp or flow action. For the output, again select number, and I named mine outputNumber .

the formula should be: add(triggerBody()[‘number’],triggerBody()[‘number_1’])

Name the Flow as Flow do Math, and save it. You can test the Flow simply by clicking the Test button and supplying two input values. The Flow can be named something different, but this name aligns with the below example.

Back in the PowerApp, click the Power Automate icon.

With the Power Automate window open, click on Add flow and select the newly created Flow, or search for it and select it.

On the app design surface, select the button and update its OnSelect property to:
Set(varNumber, FlowDoMath.Run(TextInputOne.Text,TextInputTwo.Text).outputnumber)

Select the LabelMathResult field and set its Text value to varNumber

Run the app, input values in the text fields, then click the button.

What just happened?


The values of the two text input fields were passed to the Flow, it added them together and returned the value in the outputnumber field; that value was then set to the varNumber variable.

In future posts, I will dive deeper into more complex examples.



How do you find ALL the Flows that reference a SharePoint site or list?

I asked this question when I first started down the path of learning about Flow:
How do you find all the Flows running on or referencing a SharePoint list?

UPDATE / EDIT – READ THIS Part
Before you start on this, please ensure that your account or the account you are using to run the script has sufficient permissions to the target environment(s).

$oneFlow = Get-AdminFlow -FlowName "00000-ae95-4cab-96d8-0000000" -EnvironmentName "222222-4943-4068-8a2d-11111111"

$refResources = $oneFlow.Internal.properties.referencedResources
Write-Host $refResources



If you run that command and look at the returned properties and see an error, that means you do not have the correct permissions to move forward. You can check your permissions in the Power Platform admin center: https://admin.powerplatform.microsoft.com/

/end of update

Think about it: someone in your company creates a Flow that runs when a SharePoint item is updated. Fast forward a year or so, and that coworker has moved on, and the Flow needs to be updated. If you work for a small company or one that hasn’t fallen in love with Power Platform and Flow, you’re likely in luck, and finding the Flow will take a few minutes. In my case, there are currently 2,712 Flows in my tenant that span several environments.

The PowerShell script I’ve created will query a tenant using the Get-AdminFlow command, return all Flows, and then loop through them. The script can be adjusted to target a single environment using the EnvironmentName parameter. Note: running the script using the Get-Flow action will return all the Flows your AD account can access.

#Install-Module AzureAD
#Install-Module -Name Microsoft.PowerApps.Administration.PowerShell  
#Install-Module -Name Microsoft.PowerApps.PowerShell -AllowClobber 

#connect-AzureAD

function Get-UserFromId($id) {
    try {
        $usr = Get-AzureADUser -ObjectId $id
        return $usr.displayName
    }
    catch {
        return $null
    }
}

#get all flows in the tenant
$adminFlows = Get-AdminFlow 

#set path for output
$Path = "$([Environment]::GetFolderPath('Desktop'))\Flow_Search_for_SharePoint_$(Get-Date -Format "yyyyMMdd_HHmmss").csv"

#set target site
$targetSPSite = "https://yourTenant.sharepoint.com/sites/yourSITE"
$targetSPList = "4f4604d2-fa8f-4bae-850f-4908b4708b07"
$targetSites = @()

foreach ($gFlow in $adminFlows) {

    #check if the flow references the target site
    $refResources = $gFlow.Internal.properties.referencedResources | Where-Object { $_.resource.site -eq $targetSPSite }

    #check if the flow references the target list
    #$refResources = $gFlow.Internal.properties.referencedResources | Where-Object { $_.resource.list -eq $targetSPList }

    if ($refResources -ne $null) {

        #optional - get the user who created the Flow
        $createdBy = Get-UserFromId($gFlow.internal.properties.creator.userId)

        $row = @{}
        $row.Add("EnvironmentName", $gFlow.EnvironmentName)
        $row.Add("Name", $gFlow.DisplayName)
        $row.Add("FlowEnabled", $gFlow.Enabled)
        $row.Add("FlowGUID", $gFlow.FlowName)
        $row.Add("CreatedByUser", $createdBy)
        $row.Add("CreatedDate", $gFlow.CreatedTime)
        $row.Add("LastModifiedDate", $gFlow.lastModifiedTime)
        
        $targetSites += $(new-object psobject -Property $row)
    }
}

#output to csv
$targetSites | Export-Csv -Path $Path -NoTypeInformation

If you don’t want to get the display name of the user who created the Flow, comment out the part of the script that calls the Get-UserFromId function, and you won’t need to connect to Azure.

And to answer my original question: How do you find all the Flows running on or referencing a SharePoint list?
In the script, comment out the part of the script that references $targetSPSite and un-comment $targetSPList. You can get the GUID of the list by navigating to list settings and looking at the URL. Another option is to open the list, view the Page Source, then look for the “listId” property.

In a future post(s), I will outline how to search for all Flows that use different connectors, Dynamics 365 tables (dataverse), triggered from Power Apps, or other objects. All of the info is in the properties of the Flow; getting to it can be a little fun.

Use a Power Automate Flow to Scrub File Names of Unwanted Characters

Last year, my team rolled out a Power App Portal (Power Pages) to allow customers to submit requests with attachments. The attachments are stored in Azure Blob Storage, and we use Cloud Mersive to virus scan the submitted attachments. Not to get too deep into the weeds, the process flows like this:
Attachment is uploaded –> lands in the Dataverse Note (annotation) table –> then is shipped to blob storage

Now the problem: users can name a file whatever they like and upload them. This quickly became an issue due to Flow not always being able to find the blobs associated with the request if the filename contained some special characters. Example: MyTrademark®.pdf

There are some great examples online for replacing special characters with a space or another supported character, but I wanted to take a different approach that seemed a lot more efficient to me. Where my example differs is the use of the Filter Array Flow action to only check the characters of the filename, as opposed to looping through each letter of the alphabet and comparing it to each letter in the filename.

Here’s the completed Flow, but I’ll dig into each step in this post.

The Compose Chars action holds the array of characters I will use to validate the characters in the supplied filename. This can be shortened if the input filename is to be set to uppercase or lowercase; only one set of the alphabet is needed.

[{"Char":"A"},{"Char":"B"},{"Char":"C"},{"Char":"D"},{"Char":"E"},{"Char":"F"},{"Char":"G"},{"Char":"H"},{"Char":"I"},{"Char":"J"},{"Char":"K"},{"Char":"L"},{"Char":"M"},{"Char":"N"},{"Char":"O"},{"Char":"P"},{"Char":"Q"},{"Char":"R"},{"Char":"S"},{"Char":"T"},{"Char":"U"},{"Char":"V"},{"Char":"W"},{"Char":"X"},{"Char":"Y"},{"Char":"Z"},{"Char":"a"},{"Char":"b"},{"Char":"c"},{"Char":"d"},{"Char":"e"},{"Char":"f"},{"Char":"g"},{"Char":"h"},{"Char":"i"},{"Char":"j"},{"Char":"k"},{"Char":"l"},{"Char":"m"},{"Char":"n"},{"Char":"o"},{"Char":"p"},
{"Char":"q"},{"Char":"r"},{"Char":"s"},{"Char":"t"},{"Char":"u"},{"Char":"v"},{"Char":"w"},{"Char":"x"},{"Char":"y"},{"Char":"z"},{"Char":"0"},{"Char":"1"},{"Char":"2"},{"Char":"3"},{"Char":"4"},{"Char":"5"},{"Char":"6"},{"Char":"7"},{"Char":"8"},{"Char":"9"}]

Compose Org Filename: string('my super 123 longer $%^&^ file /// name ^^^ with junk in it.xlsx')
Compose Split Extension: last(split(outputs('Compose_Org_Filename'), '.'))
Compose Concat Extension: concat('.', outputs('Compose_Split_Extension'))
Compose Get Filename: split(outputs('Compose_Org_Filename'), outputs('Compose_Concat_Extension'))[0]

The point of the Apply to each loop is to iterate over each item in the filename. Note: I’m using a Chunk function to break apart the filename. I first tried using a Spilt function, but there would be no end to what the delimiter might be.

Apply to each: chunk(outputs('Compose_Get_Filename'),1)

Filter array Chars: From: Compose Chars
char is equal to Current item
Here is the advanced view of the action:
@equals(item()?['char'], items('Apply_to_each'))
If you think of it like a SQL statement, it would be:
Select * from Compose Chars Where Char = Current item
The filter checks if the current item in the apply to each loop is in the Compose Chars array.

Condition: empty(body('Filter_array_Chars')) is equal to true
If the current item is not in the array, skip it (yes), else start building the filename (no)

This hack is needed due to not being able to set a Flow action equal to itself. Think of it like a programmatic iteration. i++ or i = i + 1

Compose Temp is a placeholder for the varNameBuilder variable.
Set variable Name Builder: concat(outputs('Compose_Temp'),items('Apply_to_each'))


Compose Clean Filename: concat(variables('varNameBuilder'),outputs('Compose_Concat_Extension'))

Copy of the Flow can be downloaded here:
https://www.sharepointed.com/wp-content/uploads/2023/02/FilenameScrubber_20230227.zip

Things to consider:
Empty filename –
What if the filename is nothing but special / unwanted characters? At the end of the Flow, you’d want to use a Length function to check varNameBuilder to see if it’s greater than X.
example: !@#@$#$%%^&.pdf
The result from the Flow would be .pdf, and updating the filename would fail. To my knowledge, you can’t name a file like that, but you get the point.

Also, I’ve had users upload files with non-English characters, so there is a viable chance that someone, at some point, might upload a file like this: 我喜欢炸玉米饼.pdf

Making the Flow available to other flows –
If the Flow is created in a solution, it could be used more like a function, and other Flows in the solution could reference it. This would be a great example of a reusable Child Flow.

Flow and SharePoint Online Large Libraries

Using Flow to get or check for files in a large SharePoint library can be a little tricky. If you are sure your library will always stay under 5,000 items the Get Files (properties only) Flow action is a quick n’ simple approach to use. When your library crosses over the mythical 5k mark or somewhere in that neighborhood, the Get Files action will fail to return results without warning. What I’m outlining below are other options when working with large libraries.

Setup:



Option 1: Get Files using an Odata filter query
downside: only use this in small libraries



Result:


Option 2: use the SharePoint API
downside: the lack of transparency from Microsoft related to how often data is crawled.

Result:

Option 3: use the SharePoint API along with a filter action on the library. This option does require that you have metadata set up on the library to filter on and there is not a wildcard / contains option. The filtered value needs to be exact.
downside: you will need to set up your metadata ahead of time or create it after the fact then backfill.

Result:

The more I learn about Flow and SharePoint Online, the more I’m starting to like Option 3 when doing a lookup type of search. SharePoint Search is an extremely powerful tool if the search index is fresh.

Get and Set SharePoint Yes No Field Using Flow

Simple question: Using a Flow condition, how do you check the value of a SharePoint Yes No field?

My first attempt was to set a variable equal to the SharePoint list value, then check the condition like this:



And, for good reason, this did not work.
My next attempt was to try replacing the condition value with true or false.



And, again, this did not work!
Sooo, what if I convert the true or false to a string?


It worked!



How do you set or update a SharePoint Yes No field using a Flow variable?


Create a string variable, then set the value to true or false.
SharePoint display values:
Yes = true
No = false


Flow Variables Not Displaying In The Dynamic Content Menu

I was trying to dynamically set a SharePoint list item ID to a variable but the variable was not displaying in the Dynamic Content menu.

The solution was to use an expression to set the value, save the flow, exit the edit screen, then re-enter the edit screen.

variables('varRefID')
Create a variable
Notice the variable is not available for selection
Use the expression window to enter the variable name
The variable has been added but looks weird. This is not an issue but continue reading if you want to clean display value.
Save your flow and exit the edit screen.
Edit your flow
The variable is now displayed correctly!

Power Automate Bad Gateway Error

I was trying to use a SQL Insert Row action to insert a new row in a SQL Server table and received a Bad Gateway error. First, I thought it was a permissions issue, then I thought my Flow stopped working…

Turned out to be an issue with the amount of data being inserted into a field. One SQL column was set to varchar(X) and the Flow was trying to insert more characters than X.