Environment Variable caching in Power Automate

In this blog post, we will talk about Environment Variable caching in Power Automate, what the problem is with it and how to work around it.

I have attached both a managed and unmanaged solution containing the complete flow to this post. You can find the link furthure down at the bottom of this page.

Background

As of writing this blog post (2022-02-22) Power Automate Flows do cache environment variables. This applies to Flows using the out of the box Environment Variable integration, basically use an EnvVar directly from the list of available EnvVars.

Adding EnvVar OOB
Adding EnvVar OOB

If you happen to change the value of an environment variable it will not be used by any Power Automate Flow until you turn the flow off and on again.

This behaviour has cost me already quite a lot of time and hair.

Structure Environment Variables

Before we go into detail regarding the solution I would take a moment to explain how Environment Variables are structured. This is needed to understand what my solution will query from Dataverse.

An Environment Variable can basically consist of two parts.

  • Environment Variable Definition
  • Environment Variable Value

The definition contains all the needed information to define a Environment variable.

  • Display Name
  • Schema Name
  • Description
  • Data Type
  • Default Value

The Value (I tend to call it local value) only contains a environment specific value which should override the default value.

Microsofts idea behind it is that the definition is part of a solution, where as the value should not be. When the solution is then moved to the downstream environment one can present a local value. This will (in the OOB integration) override the default value if present. One of both (either default value or local value) has to be present at any time, otherwise the maker portal will show a small error on the top of the page.

Solution

The solution I tend to use to tackle this problem is to create a child flow. This flow would take the Environment Variable SchemaName as an input and respond with the correct value. I would then call the child flow within my flows whenever I need the value of an Environment Variable.

You could also install/create a custom API or Action to do the job and call that from within your flow. One example of such an custom API is the GetEnvironmentVariable from David Rivard (LinkedIn & Twitter). Creating one needs a developer and installing third party APIs might not be allowed by your IT Department. That’s when the flow solution I mentioned comes into the picture.

In either way our solution has to follow the idea described earlier. When a local value is present this should be responded with if not we will take the default value.

Flow

Let’s get the actually flow build.

Create & Trigger

First we create a new instant flow using a Manuall trigger as well as choosing a good name.

Flow Basic - Create Flow
Flow Basic – Create Flow
Flow Basic - Name & Trigger
Flow Basic – Name & Trigger

In the trigger we add “EnvVarName” as an input of type text.

Flow Basic - Trigger
Flow Basic – Trigger

Load EnvVar definitions

As the fist step we add a List rows action from the Dataverse connector.

In the Table we select “Envrionment Variable Definitions”, Row count should be 1 and in Fetch Xml Query we add the following fetch XML.

<fetch top="1">
<entity name="environmentvariabledefinition">
<attribute name="defaultvalue" />
<attribute name="type" />
<filter type="or">
<condition attribute="displayname" operator="eq" value="@{triggerBody()['text']}" />
<condition attribute="schemaname" operator="eq" value="@{triggerBody()['text']}" />
</filter>
<link-entity name="environmentvariablevalue" from="environmentvariabledefinitionid" to="environmentvariabledefinitionid" link-type="outer" alias="value">
<attribute name="value" />
</link-entity>
</entity>
</fetch>

This will load the first environment variable definition which has the input text either as displayname or schemaname. It will also get the environment variable value if present.

I wasn’t able to reproduce the same behaviour just with OData, since one can’t have a outer link type. In that case the result was empty when no EnvVar value was present. Therefore we are using the fetchxml instead.

Basic Flow - Load Records
Basic Flow – Load Records

Init variable

This step isn’t necessary but makes the “extension”functionalities easier. We initialize a variable called “RespondValue”.

It should contain the environment variable value if present and the default value in other case. To achieve that we use the following powerFx expression as the Value.

if(empty(first(outputs('List_EnvVarDefinition')?['body/value'])?['value.value']), first(outputs('List_EnvVarDefinition')?['body/value'])?['defaultvalue'], first(outputs('List_EnvVarDefinition')?['body/value'])?['value.value'])
Basic Flow - Init variable
Basic Flow – Init variable

Respond with Value

Last step would be to respond with the content of the variable. To do that we add a step “Respond to a PowerApp or flow” from the Power Apps connector.

The output should be called “EnvVarValue”, of type text and be the variable we just created.

Basic Flow - Respond
Basic Flow – Respond

Add more functionality

Now that we have the basic flow we could add more functionality. I would like to explain two more features I tend to implement.

Secret

When the Environment Variable is of type Secret the value has to be loaded in a different way. In that case Microsoft provided an unbound Action one could call to get the secret value. The Action would get the value from the configured Azure Key Vault.

What we have to do is to check the Environment Variable Type and call the action when it is a Secret.

To do that we add a Condition step where we take the type of the first value of the list row response and compare it to the ID of the Secret Type (which is 100000005). With the following expression you will get the id of the type of the first row in the list rows step.

first(outputs('List_EnvVarDefinition')?['body/value'])['type']
Secret - Condition
Secret – Condition

In the true path we will add a step of type “Perform an unbound action” of the Dataverse connector. In the field “Action Name” we select “RetrieveEnvironmentVariableSecretValue”, which is a Action provided by Microsoft. As the Input we send in the input from our trigger.

Secret - Get Secret
Secret – Get Secret

On the same step we would like to secure the output since we already know it’s some kind of secret. To do that we select the three dots and click on Settings.

Secret - Open Settings
Secret – Open Settings

On the next screen we make sure the second flip switch is true.

Secret - Secure Output
Secret – Secure Output

Lastsly we have to set the just received value to the variable we created earlier.

Secret - Set Variable
Secret – Set Variable

Casting

An Environment Variable could be of one of different data types.

EnvVar Data Types
EnvVar Data Types

The current solution will always have the value it responds with as type String/Text. What you might want to have is the value casted to the actual type.

I am not aware how the type “Data source” should be casted. Please feel free to let me know if you do.

Since JSON also just is a different form of Text we don’t have to cast that. Neither do we have to do anything with Secret since that is already handled in the previous chapter. What left is the cast to a decimal number and a Yes/No (or boolean).

All we have to do to achieve this is adding two new outputs to our Respond step. One called “EnvVarValueBool” and one called “EnvVarValueNumber”.

The following expression will cast the value to a boolean if the type is yes/no.

if(equals(first(outputs('List_EnvVarDefinition')?['body/value'])['type'],100000002), if(equals(toLower(variables('RespondValue')), 'yes'), true, false), null)

Here is the expression to cast the value to a float if it is of type Decimal number.

if(equals(first(outputs('List_EnvVarDefinition')?['body/value'])['type'],100000001), float(variables('RespondValue')), null)
Cast - Response
Cast – Response

Problems

There are some problems or at least things to take into consideration when you implement the solution I have described earlier.

  • You will get more flow runs impacting both your API limits and license.
  • The value from a EnvVar of type Secret isn’t secured when send to the parent flow.
  • It is more complicated to get the casted value than using the OOB integration

Conclusion

As you can see there is a solution to the described problem of environment variable caching in Power Automate. It might not be the easiest or pretiest one, but it is working as expected. I hope that Microsoft will change the implementation of the OOB integration to get rid of the caching.

Either you use the OOB functionality and the value is cahced or you accept the mentioned problems and always get the actually value. One has to decide which cons are easier to accept and implement the solution accordingly.

I hope this post helped you. Feel free to contact me with any question or feedback you have.

Attachments

This is just 1 of 50 articles. You can browse through all of them by going to the main page. Another possibility is to view the categories page to find more related content.
You can also subscribe and get new blog posts emailed to you directly.
Enter your email address to receive notifications of new posts by email.

Loading

Add a Comment

Your email address will not be published.