Power Automate: How to get previous versions in SharePoint

There are a lot of valuable triggers for SharePoint list items, like the “When an item is created or modified” trigger. They help us understand when something changes so that we can perform actions to the data. But something else that is important is to understand “what” changed. This is because SharePoint lists can have a lot of columns and, depending on the one that changed, we need to react to it. So today, we’ll explore how to check if something changed by fetching the previous versions of the list item.

Before we start, you must check if your list has the versioning activated. As a good practice, activate it or at least read my article about what happens when you say, “My data disappeared! How to recover it?”.

As always, you have here the template to download and try for yourself now. If you want to know more keep on reading.

How to get previous versions of data in a list

There are times when it’s helpful to fetch the previous versions, so this template will help you do that.

Let’s check the details of the template, but first, here’s a global overview of the template.

Check if it was created or updated

Using the “When an item is created or modified” trigger, we have a trigger that fires when something happens on the list.

We have two columns (“Created” and “Modified”) that SharePoint updates automatically. They contain the date that the item was “Created” and when it was last “Modified.” Please note that SharePoint also considers something as “modified” when an item is created, so both dates are the same when it happens. So we can use a simple “Condition” action to check this:

You can then take adequate actions depending on what happened.

Check what was updated

SharePoint stores changes with version numbers. The numbers are defined by a major and minor version separated by a comma. So if you have “1.2”, then the major version is one, and the minor is two. Of course, we only have major versions in the case of lists, but I want you to understand why the number is built this way.

So let’s get the previous version. To do that, we need to:

  1. Fetch the current version number
  2. Fetch all previous versions
  3. Search for version – 1

Get the last number version

First, we need to create the last number, but since the version is returned as a string, we need to break it into two parts (major and minor version) and get the number.

Here’s the formula:

int(first(split(triggerOutputs()?['body/{VersionNumber}'],'.')))

So what’s happening here? First, we split the version string into two parts using the split function. For example, if we have “5.0”, we’ll get an array with “5” and “0”. Since we only want the first item, we’ll use the first function. After that, we convert to an integer using the int function.

Now that we have a version number let’s calculate the previous value using the “sub” function.

Here’s the formula:

sub(outputs('Get_the_current_version_number'),1)

Finally, let’s create the new version number string using the “concat” function.

Here’s the formula:

concat(outputs('Get_the_previous_version_number'),'.0')

Get the previous versions

To get the previous versions, we’re going to use the “Send an HTTP request to SharePoint” Action since we don’t have an action to get versions “out of the box.”

The URI looks a bit daunting, but this is defined by Microsoft. Power Automate does a great job hiding this from us, but in this case, we need to go a bit “deeper” and built it ourselves. So let’s read it to underhand what’s happening:

_api/web/lists/getbytitle('CreatedAndModified')/items(@{triggerOutputs()?['body/ID']})/versions/

Let’s use SharePoint’s web API (_api/web/) to get the list named “lists/getbytitle(‘CreatedAndModified’)” with the item number (items(@triggerOutputs()?[‘body/ID’])) and get it’s versions (/versions/)

It doesn’t look too bad now.

Find the previous version.

We get an array with all versions in JSON format. Since Power Automate doesn’t know what comes from the “Send an HTTP request to SharePoint” Action, we need to give it the structure to parse it in the following action.

Pro Tip: To generate the structure run your Flow once and get the result from the “Send an HTTP request to SharePoint” action. Copy that and paste it into the “generate from the sample” in the “Parse JSON” action, and Power Automate will do all the work for you.

Now that we have an array, we can use the “Filter” action and get the version’s information:

Check what changed

Now that we have done all our homework, it’s easy to check what changed. We have the previous data and the current version, so you only need “Condition” actions to compare the data. For example:

That’s it. All the work is done on the previous steps, so we only need to compare data and act on it.

That “Apply to each” is ugly.

I agree. Since we’re filtering an array, we always get an array in return, even if it only has one row. But since we get an array, we need the “Apply to Each” action. But we can solve it with:

  1. Condition to check if we have data.
  2. If we do, get the first element and use it to compare.

Finally, the template won’t contain this change to keep things simple, but you can change it, depending on what makes sense for you. Here’s the code for the additional section. To import it, you can check my article about “copy and paste.”

{
    "id": "88d9d877-c5aa-4458-8a1d-b0ca-ba8f394f",
    "brandColor": "#484F58",
    "connectionReferences": {
        "shared_sharepointonline": {
            "connection": {
                "id": "/new_sharedsharepointonline_5bf5e"
            }
        }
    },
    "connectorDisplayName": "Control",
    "icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZlcnNpb249IjEuMSIgdmlld0JveD0iLTQgLTQgNjAgNjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQogPHBhdGggZD0ibS00LTRoNjB2NjBoLTYweiIgZmlsbD0iIzQ4NEY1OCIvPg0KIDxwYXRoIGQ9Ik00MSAxOC41di03LjVoLTMwdjcuNWg1LjY0djEzLjgzbC0zLjI4NS0zLjI4NS0xLjA2NSAxLjA2NSA0LjAzNSA0LjA1Ljg3Ljg0aC02LjE5NXY2aDEzLjV2LTZoLTYuOWwuODU1LS44NTUgNC4wMzUtNC4wNS0xLjA2NS0xLjA2NS0zLjI4NSAzLjI4NXYtMTMuODE1aDE1djEzLjgzbC0zLjI4NS0zLjI4NS0xLjA2NSAxLjA2NSA0LjAzNSA0LjA1Ljg3Ljg0aC02LjE5NXY2aDEzLjV2LTZoLTYuOWwuODU1LS44NTUgNC4wMzUtNC4wNS0xLjA2NS0xLjA2NS0zLjI4NSAzLjI4NXYtMTMuODE1em0tMjguNS02aDI3djQuNWgtMjd6IiBmaWxsPSIjZmZmIi8+DQo8L3N2Zz4NCg==",
    "isTrigger": false,
    "operationName": "Check_if_I_have_a_value_after_the_filter",
    "operationDefinition": {
        "type": "If",
        "expression": {
            "equals": [
                "@length(body('Filter_array'))",
                1
            ]
        },
        "actions": {
            "The_unique_value": {
                "type": "Compose",
                "inputs": "@first(body('Filter_array'))",
                "runAfter": {}
            },
            "Example_-_Get_the_title": {
                "type": "Compose",
                "inputs": "@outputs('The_unique_value')?['Title']",
                "runAfter": {
                    "The_unique_value": [
                        "Succeeded"
                    ]
                }
            }
        },
        "runAfter": {
            "Filter_array": [
                "Succeeded"
            ]
        }
    }
}

Final thoughts

The template looks a bit complex, but you can easily understand the power of getting the previous versions when you know the actions. You can do things like a warning if something changed and what, never to the earlier changes if a change is incorrect, and more.

Go ahead and download the template and let me know what you think and how you used it.

Have a suggestion of your own or disagree with something I said? Leave a comment or interact on Twitter and be sure to check out other Power Automate-related articles here.

Photo by Ross Findon on Unsplash

Manuel Gomes

I'm a Project Manager with experience in large projects and companies. I've worked in the past for companies like Bayer, Sybase (now SAP) and I'm currently working for Pestana Hotel Group.

View all posts by Manuel Gomes →

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: