Skip to main content

Using Custom Connectors and Microsoft Graph API's to Manage Licenses in Power Automate - Part Two

Hello again! Didn't I promise you that I'd be back to wrap this up? Well, here I am to give you the second tidbit of information that you need to get this started. If you haven't already, take a look at my previous post where I go into depth about creating a custom connector in Power Automate to retrieve the latest sign-in and also gather the user's licenses. Now that we have the custom connector ready, we can now get into the meat n' potatoes of this series. In this post, I will show you the flow that makes this possible and how you can use the custom connector you have created to tie it all together! Hope you enjoy.


Understanding the Logic

Before we can begin creating the flow, we should first understand how the flow will work. I designed this to flow to be triggered manually, but you may want to schedule it or use another trigger. The trigger will depend on your organization's policies, so please adjust accordingly. Once triggered, the flow will use the Entra ID connector to retrieve users from a specified group which contains our license holders. For each of these users, we will then use our custom connector to retrieve their last sign-in and then use a conditional to determine how many days have elapsed since their last sign-in. If the number of days is over a certain threshold, then we will remove them from the group, therefore removing their license. 

If we put this into a diagram, this is what the logic would look like:
I find that prior to doing any Power Automate flow, or building a Power App, that building a flowchart like this is a very great help. Not only does it help to put your idea on paper, but it also allows for you to think out how the flow will look and address any potential issues before you begin implementing. Now let's translate this into an actual flow!

The Flow Itself

Now that we understand the logic, we can begin to dish out the actual Power Automate flow. I should mention that the flow itself will differ from the flowchart logic we have above, the flowchart is just a stencil to give us some direction on how the flow should work. The actual flow itself involves quite a bit of stuff to satisfy our flowchart, but if you compare the two you will find similarities:

If we put this flow into a sequence of events, this is what happens:
  1. The flow is manually triggered by the flow owner
  2. A variable is initialized to store the number of days since last sign-in
  3. Group members are retrieved from the group we specify
  4. For each group member we then do the following:
    1. Use our custom connector to get their last sign-in
    2. Parse the JSON response that is given to use from the Microsoft Graph API
    3. Compose the content and retrieve the date and time from the parsed JSON
    4. Add the group member's information and sign-in to a SharePoint list
    5. Get the group member from the SharePoint list and their sign-in date
    6. Use a conditional to determine if the number of days that have elapsed is 90 or beyond
    7. Remove the user from group if beyond 90 days, effectively removing their license.
Now, let's break down the flow down even further into each of their respective parts so that we can get this flow built:

Initialize Variable - Number of Days

First and foremost, we must initialize a variable to hold the number of days, I created an integer variable called "DaysCount" and left it blank (null) for now as we are just initializing it for now:

Get group members 

Now, let's get our group that contains the licensed users! If you haven't already, now would be a good time to create a group and assign licenses to them. Assuming you already have these groups ready, let's get this started:

Apply to each

We can now take the output from getting our group members and use that to apply the rest of the flow to each of the group members recursively:

License PA Connector - Get Last Sign-In

Next, we will get the ID for each group member and then use the $select parameter to get the latest sign-in activity:

Which in turn will produce the following results if configured correctly from our last post:

    "body": {
        "@odata.context""https://graph.microsoft.com/v1.0/$metadata#users(signInActivity)/$entity",
        "id"".........",
        "signInActivity": {
            "lastSignInDateTime""2025-06-08T01:46:01Z",
            "lastSignInRequestId""..........",
            "lastNonInteractiveSignInDateTime""2025-06-08T04:06:46Z",
            "lastNonInteractiveSignInRequestId""............",
            "lastSuccessfulSignInDateTime""2025-06-08T04:06:46Z",
            "lastSuccessfulSignInRequestId"".........."
        }
    }
}

Parse JSON

So now that we have the body of the output from our request, we can now begin to parse it and get what we need. I took the body of the output from the request and then used that to generate a sample payload which looks like so:

    {
    "type": "object",
    "properties": {
        "signInActivity": {
            "type": "object",
            "properties": {
                "lastSignInDateTime": {
                    "type": "string"
                }
            }
        }
    }
}

This is what it looks like in the action itself:

Compose JSON

Let's now take the JSON that we have parsed and select what we need. For this we will use the following input to get exactly what we need:

@{body('Parse_JSON')?['signInActivity']?['lastSignInDateTime']}

If you wish, you can also select this from the dynamic content section as well if it appears. If it does not, double-check your flow and ensure that you haven't missed a step.

Add to List

Finally we can begin populating a SharePoint list with the information we have gathered so far. To do so, create a list that will contain the following columns and datatypes:
  • UPN - Single line of text
  • Last Sign-In Date - Date (do not include time)
Once this is done, we can then incorporate this into our flow with an "Add to List" action as so:

Get Item

Let's now get that item in particular and then use that item in subsequent parts of our flow:

Set Variable

Setting the variable we created above will allow for us to determine the number of days. However, there is a specific value that is needed to make this happen. Insert the value below to count the number of days and return an integer:

@{div(sub(ticks(utcNow()), ticks(outputs('Get_item')?['body/LastSignInDate'])), 864000000000)
}


Conditional

We will now use the output from our set variable to determine if the count is greater than or equal to 90 days. If true, it will remove the user from the group as seen in the flow. False, and it will continue with the next user:



Conclusion

We have successfully created a custom connector that retrieves the information we need to manage our licensing. Hope that you enjoyed this post! In the next article, we'll be swinging back to my latest project PIM-IT, where I will give you the updates on this ongoing project for Privileged Identity Management. Until next time folks!


test

PIM-IT Ver 0.0.2: More features and Activation Packages

Hello everyone! Hope you're having a great long weekend so far, while I type this I am in my bed with my dog and pushing the latest updates to my GitHub. It's been a minute since I last posted but I wanted to take the opportunity to give you all an update on the PIM-IT project, the PowerShell tool for streamlining Privileged Identity Management. Consider this if you will a changelog of sorts, in which I will talk about the latest features, some takeaways, and what is next in the project. Let's get started! PIM-IT Ver 0.0.2 Latest Features The first major update is the ability to deactivate and update roles. This is a major step towards giving users full control of managing PIM roles from initial activation to deactivation. Updating PIM Roles To update a PIM role, the user selects option "U" from the menu, which will then display currently active roles: From here, the user will select the PIM role they wish to update, which will allow them to adjust the duration to...

Introduction to the PIM-IT Project: Version 0.0.1

Hey everyone! It’s been a while since my last update, but I’m back this Easter weekend to share some exciting work happening behind the scenes. One of my latest projects is PIM-IT , an open-source tool designed to simplify Privileged Identity Management (PIM) in Microsoft Entra . What is PIM? Privileged Identity Management (PIM) helps manage access to roles within Microsoft Entra, ensuring just-in-time access to privileged roles like User Administrator . PIM enhances security by granting access only when needed, for a limited time, under admin-defined conditions. It also helps prevent unauthorized privilege escalation and provides a valuable audit trail. When used correctly, PIM is a powerful tool for managing roles and permissions efficiently. Why PIM-IT? While PIM strengthens security, the process of assigning roles can be tedious—logging into the Azure portal, finding eligible roles, assigning hours, providing justification, and waiting for activation. Now, imagine doing this dai...

Making a SharePoint Knowledge Base Part One: Getting Our Ducks in a Row

Howdy everyone, it's great to be back again for another post! As a matter of fact, this is our very first post on this blog. Amazing! For this post, I am going to help you create an intuitive Knowledge Base in SharePoint that your department or company can use as a whole. We'll also use Power Automate to notify us when our team adds to our Knowledge Base. So with this in mind, let's get started! Why a Knowledge Base? This idea comes from a recent SharePoint migration I did in my own workplace. I wanted to create a centralized resource for our team to find knowledge articles, troubleshooting steps, and guides. This helps us share knowledge across our team as well as with our end-users. For those of you who do not know what a Knowledge Base is, it is as simple as this: A centralized resource to share knowledge and provide self-help to users.  Now that you're privy to what it is, we can begin to build ourselves a Knowledge Base! We'll start with our foundational assets...