Get deleted SharePoint site details using Microsoft Graph API

The deleted sites are retained for 93 days and an Admin can restore them. In this blog post let us see how to get the deleted SharePoint site details using Microsoft Graph API application permission.

Step 1: Register an application in Azure AD and obtain the client id, client secret & tenant id for the registered application. Add Sites.Read.All Microsoft Graph application permission

Step 2: Find the list GUID of the Hidden List DO_NOT_DELETE_SPLIST_TENANTADMIN_ALL_SITES_AGGREGA which has all the deleted site information from the tenant.

Make a GET request to the following Graph API endpoint with the token generated from the above AD app using PostMan or using Graph Explorer if you are an Global or SharePoint administrator

Replace the tenantName with name of your tenant from the above URL

Step 3: Graph API to list all Deleted Sites within the tenant$expand=fields

Make a GET query after replacing the tenantName and the list GUID of DO_NOT_DELETE_SPLIST_TENANTADMIN_ALL_SITES_AGGREGA from Step 2.

You can filter from different fields available [Title, SiteUrl etc]. To filter based on SharePoint site URL$expand=fields&$filter=fields/SiteUrl eq ''

Step 4: To do this from Power Automate or Azure logic app, follow this post

There are activity alerts which you can setup from Security center for Deleted Site but it will send you information on the Site URL and the name of the user deleted the site, as of now it does not provide the Title, Site ID etc. So this API can provide you additional details. Hope you have found this informational & thanks for reading. If you are visiting my blog for the first time, please do look at my other blogposts.

Conditional Power Automate flow triggers for SharePoint Online Pages and NEWS Post

SharePoint Online Pages library is a container for different type of pages (News post, Page, Space, News Link) created in a Communication or Team site. There can be various scenarios to have a Power Automate Flow associated to a SharePoint Site pages library to handle additional processes after a Page or a News post is published. In this blog post, let us see how to

  1. Trigger the flow if a News post is published
  2. Trigger the flow only for Major versions
  3. Trigger the flow for a specific Content Type
  4. Avoid infinite trigger loop on an Item Created/Modified trigger if a page/list item is updated by the flow

using Trigger Conditions. Trigger conditions can be used on a trigger to stop your Automated Flow from running if the conditions are not met. Unnecessary flow runs can spend your quota limits based on the license types without providing any value. To begin with, create an automated cloud flow with the SharePoint trigger When an item is created or modified and configurations for the Site Pages Library. Once you provide the Site URL where your Site Pages library exists, you will notice the Site Pages library doesn’t show in the drop-down. In the List Name property, just provide the guid of the library instead.

To get the guid, browse to the Site Pages library on the SharePoint site, go to Library settings and select the value after the List= parameter on the URL after decoding.

Trigger the flow if a News post is published

There can be scenarios to trigger the Flow when a News post is created or modified. A SharePoint property PromotedState can help identify if the SharePoint page is a News post or a normal page since all the different types of pages are stored in the same library.

LabelValueWhat it means
NotPromoted0Regular Page
PromoteOnPublish1News post in draft mode
Promoted2Published News post

The trigger condition will make sure the trigger is fired only when ever there is a News Post is published or Saved as draft (All Major and Minor versions).


Now add the above trigger condition in the settings of the trigger as shown below

The above trigger condition will have the flow triggered for all major versions (1.0, 1.1 .. 2.0, 2.1, ..).

There can be multiple trigger conditions which accepts Boolean value (True or False), all conditions must be True for the trigger to fire.

To trigger the flow only on first Published version of the flow, add the following trigger condition.


To trigger the flow only on major versions and on News post, add the following trigger condition


Trigger the flow only for Major versions

The following trigger condition will make sure to fire only for Major versions (1.0, 2.0, 3.0 etc) and not for minor versions aka draft version (0.1, 0.2 etc)


Trigger the flow for a specific Content Type

Content types in SharePoint are a set of columns that are grouped together to serve a specific type of content (Crisis News, Marketing News etc). A Page or a News post in a SharePoint site can be associated with content types. The trigger condition for the flow to be triggered only for a specific content type is

@equals(triggerOutputs()?['body/{ContentType}/Name'], 'Name of the Content Type')

Avoid infinite trigger loop on an Item Created/Modified trigger if a page/list item is updated by the flow

In your Automated cloud flow, if you have the Created or Modified trigger with an action to update the same item then there will be an infinite trigger loop.

The Flow checker will provide you a warning Actions in this flow may result in an infinite trigger loop. To overcome the above warning, trigger condition to the rescue.

How it will be done

The update item action on the flow should use a different connection (Service Account) in the flow, other than the user who will be using the site to create or update pages. The trigger condition will make sure the flow run will not happen if the update to the Page or News post is done by the service account using the Update item action. SharePoint Library and List has the out of the box column Modified By which holds the information on who has recently updated the item be it from the SharePoint UI or through program. The trigger condition will be written based on this column Modified By, if the column value has a different value other than the service account then the flow will be triggered.

Step 1: Create a service account with password never set to expire. Licenses are not required for this account if the flow connection is going to be used only on SharePoint connectors. Password setting Never Expires will make sure the connection is not invalidated due to a password change on the account.

Step 2: Grant edit access for the service account to the SharePoint site. This step allows the account to updates to the List or Library item.Step 3: Add a new connection to the service account

Step 4: Add the following trigger condition to the SharePoint trigger if the service account does not have an Exchange Email License


Replace the with actual UPN of the service account.

If the service account has email address or a license to email service, then the trigger condition should be

@not(equals(triggerOutputs()?['body/Editor/Email'],' '))

Tip to write the trigger condition:

Before adding the condition to the trigger, evaluate the condition on a compose action using expressions and data fields selected from Dynamic content.

After the condition is added on the compose action, click Peek code

Copy the expression from the inputs parameter

The condition to be added on the trigger must be True for the trigger to fire.


Trigger conditions are powerful if used wisely to avoid unnecessary runs. I’ve shown some examples from the SharePoint pages library but it can be used on List trigger as well. The trigger can be written based on any data available on the trigger output. Hope you have found this informational & thanks for reading. If you are visiting my blog for the first time, please do look at my other blogposts.

Do you like this article?

Subscribe to my blog with your email address using the widget on the right side or on the bottom of this page to have new articles sent directly to your inbox the moment I publish them.

Call a SharePoint REST API as an Application in Power Automate HTTP Connector

SharePoint connector in Power Automate is very rich with various actions that can make the developers or makers life simple when it comes to interacting with SharePoint data. There might be some actions like

  • Breaking permission to a list item
  • Creating a site
  • Adding user to a SharePoint group etc

which is not possible through the SharePoint standard connector or MS Graph API as of the time I am writing this article, SharePoint REST API to rescue. The SharePoint online REST API enables developers to remotely interact with SharePoint data. There is an action Send an HTTP request to SharePoint which could come handy in many scenarios, the point to note here is the action uses the context of user aka flow creator while executing the API. In this blogpost, let us see how to call a SharePoint REST API to create a Modern SharePoint communication site as an application in a Power Automate cloud flow using the HTTP connector with the help of a Self-Signed certificate. Find below the list of steps to enable calling the SharePoint REST API using certificate credentials

  1. Creation of Self-Signed certificate
  2. Application Registration in Azure AD Portal
  3. Creation of Power Automate cloud flow with the HTTP Connector
    • Method 1: Without using Azure Key Vault
    • Method 2: Azure Key Vault to store Certificate


Creation of Self-Signed certificate:

The first step is to create a certificate. Refer to this blog post for instructions creating a self signed certificate using the PnP utility

Application Registration in Azure AD Portal:

Register an application in Azure AD and obtain the client id & tenant id for the registered application. In this example I have added the Sites.Read.All Application permission with Admin Consent to create the SharePoint communication site, this permission is more than enough to create the site as an Application. Grant appropriate permission based on the requirements, for e.g to break permission on list items grant Sites.Manage.All. Find below screenshot for your reference for granting permissions

To add the above created self-signed certificate, click Certificates & secrets under the Manage blade. Click Upload certificate > Select the certificate file MSFlow.cer > Add

Creation of Power Automate cloud flow with the HTTP Connector:

Let us see below how to access the SharePoint REST API to create a SharePoint site with & without using the Azure Key Vault.

  1. Method 1: Without using Azure Key Vault
  2. Method 2: Azure Key Vault to store Certificate

Method 1: Without using Azure Key Vault

In the cloud flow, add a Compose action to store the PfxBase64 value copied during the creation of the certificate. Now add the HTTP action to create a Modern Communication site

Request Type: POST



Key: accept

Value: application/json


  "request": {
    "Title": "Communication Site from Cloud Flow",
    "Url": "",
    "Lcid": 1033,
    "ShareByEmailEnabled": false,
    "Description": "Description",
    "WebTemplate": "SITEPAGEPUBLISHING#0",
    "SiteDesignId": "6142d2a0-63a5-4ba0-aede-d9fefca2c767",
    "Owner": "",
    "WebTemplateExtensionId": "00000000-0000-0000-0000-000000000000"

Change the SiteDesignId for the different site teamplate Topic, Showcase, Blank

Authentication: Active Directory OAuth

  • Tenant: TenantId
  • Audience:
  • Client ID: Azure AD Client Id
  • Pfx: Output of the compose action
  • Password: Certificate password given during the creation

Find below screenshot for your reference

Run the flow, it should be able to create the Site. Find below screenshot of the flow run

Method 2: Azure Key Vault to store Certificate

Azure Key Vault is a cloud service for storing and accessing secrets enabling your applications accessing it in a secure manner. Follow my blog article which I have written to call a Microsoft Graph API with Certificate using a Azure Key Vault to store the certificate


Custom Connector can be used to call a SharePoint REST api in the context of the user. If you are visiting my blog for the first time, please do look at my other blogposts.

Do you like this article?

Subscribe to my blog with your email address using the widget on the right side or on the bottom of this page to have new articles sent directly to your inbox the moment I publish them.

Handle SharePoint site creation response – The site address is unavailable

There is a possibility to change the SharePoint online site address of an existing site by a SharePoint admin or Global admin. There are different options to change the site URL from

  1. SharePoint Admin center
  2. SharePoint online management shell

I’ve recently faced a scenario recently, after renaming a site URL to from the Admin center I was still not able to use the url while trying to create another site though the url has to be available. I’ve tried to create the site from the SharePoint start page & SharePoint admin center, I was getting one of the following message

  • The site address is unavailable
  • Couldn’t create the site, please go back and try again.

SharePoint Online PowerShell to the rescue, run the following command as an Administrator after creating a site with some address from the start page or admin center to rename the URL

Connect-SPOService -Url
Start-SPOSiteRename -Identity -NewSiteUrl

Hope you have found this informational & thanks for reading. If you are visiting my blog for the first time, please do look at my other blogposts.

Control your Philips Hue Lights from Microsoft Power Platform and .NET

Philips Hue is a smart lighting solution provider with range of smart lights that can be controlled with your smart devices like your mobile phone, Google Home, Alexa etc through the applications developed by Philips. On top of applications from Philips, the Hue system also enables OAuth 2.0 to allow third party integrations to connect to Hue system resources. In this blog post, let us see how to use the Philips Hue OAuth 2.0 remote API to integrate with the Power Platform for controlling the lights.


  1. Lights connected to the Hue Bridge. Hue bridge is a device which is the brain of the Philips hue smart lighting system that links the lights to the internet.
  2. Register an account in the Philips Hue Developers portal

The first step is to create a Remote Hue API app which provides you with OAuth credentials to remote control the Hue lights.

Add Remote Hue API App:

After logging in to the Philips Hue Developers Portal, access the URL to add the App. Click on the link Add new Remote Hue API app

After entering the App name, Callback URL and the description, click the Submit button. For the callback URL I have provided the Postman browser call back url facilitating OAuth 2.0  token generation from Postman. You can also enter http://localhost/ as the callback url. Find below screenshot of the newly registered Remote Hue API app

Copy the ClientId & ClientSecret which will be required to generate access token for controlling the Hue lights. The next step is to generate the access token.

Access Token Generation:

To access a Philips Hue API endpoint to turn on/off or change colours of light, an access token is required. To generate an access token, the first step is to generate an authorization code. Construct the following URL

  • ClientId: From the app registration.
  • ClientSecret: From the app registration.
  • AppId: From the app registration, the name of the app. Per the above screenshot, it is myremotehueapp
  • DeviceId: The device identifier must be a unique identifier in a string format for the app or device accessing the Hue Remote API.
  • DeviceName: The name of the app accessing the remote api.
  • State: any string

The url should look something like

Access the URL in a browser, you will be prompted to accept or decline the permission grant to the created app.

Once the app is trusted, there will be an authorization code automatically generated on the browser address bar as shown below

Make a note of the code which will be used to generate access token. To Deactivate an existing App or see all the list of existing apps, login to

To generate an access token using Basic Authentication, make the following HTTP request using Postman or any other tool

Type: POST

URL: bsysFQ65 &grant_type=authorization_code

Replace the code value with yours generated from the authorization grant request.

Authorization Type: Basic Auth. Username should be ClientId of the App and Password should be ClientSecret

Find below screenshot from Postman with the above HTTP POST request, make a note of the access token and refresh token from the response section of the request.

The Access token is approximately valid for 7 days and the refresh token for 100 days. Let us now see, how to refresh the access token.

Refresh Access token:

The access token is valid only for 7 days, to use it beyond 7 days there must be a new access token generated using the Refresh token. Find below the request details using Basic Authentication

Type: POST


Authorization Type: Basic Auth. Username should be ClientId of the App and Password should be ClientSecret


Key: Content-Type

Value: application/x-www-form-urlencoded



Find below screenshot of the request

Besides Basic authentication, Hue Remote API supports Digest method. For more details on the remote authentication, go through the documentation

Control the Hue Lights using the generated Access token:

Till now we have seen how to register a remote API app, generate access token and to refresh it before it expires. Let us now see how to use the access token to turn on/off, change colours etc with the remote API endpoints. To enable this experience, there must be a username created first.

User Name Creation:

Find the HTTP request details to enable the Link button

Type: PUT


Body-RAW: { “linkbutton”:true }


Content-Type: application/json

Authorization: Bearer access_token

Immediately after the above request, make the following HTTP request to create the User Name

Type: POST


Body-RAW: { “devicetype”: “myremotehueapp” }

The devicetype is the appid or the name of the remote app


Content-Type: application/json

Authorization: Bearer access_token

Copy the username from the above request response.

Turn On/Off Hue Lights:

To turn On/Off the light, the first step is to get the Light no you are trying to control. To get the list of lights, make the following request with the user name generated above

Type: GET


Replace the username in the URL

Body: None


Authorization: Bearer access_token

In the above request response, the light no is 1 which is the first light on my Hue system.

To Turn On/Off:

Find the HTTP request details to turn on/off

Type: PUT


Replace the username & lightno in the URL

Body-Raw: {“on”:true} or {“on”:false}

True for Turning On and False for Turning off


Authorization: Bearer access_token

Content-Type: application/json

Set colours of the Hue Light:

The Philips Hue system uses Chromaticity to set the colour of the light. Chromaticity consists of two independent parameters, often specified as hue (h) and colourfulness, where the latter is alternatively called saturation, chroma. Find below diagram which will help you to set the colour of the light

Find below HTTP request details for setting the colour to RED

Type: PUT


Replace the username & lightno in the URL


        "xy": [
  "transitiontime": 0

Change the XY values for different colours. To increase/decrease brightness update the bri attribute. With the help of the above diagram, for colour GREEN the XY value is 0.350000, 0.550000


Authorization: Bearer access_token

Content-Type: application/json

For information on the Light API, refer to the documentation

Control Lights in Power Platform:

As you have seen above, to control the lights an access token and username is required. Store the information in a SharePoint list which will make it easier to get the Client Id, Client Secret, light no, refresh token etc. Find below the list schema I have created to manage the Light configuration.

Refresh the Access Token:

As the token is valid only for 7 days, create a scheduled Power Automate cloud flow which can run once in 6 days to create a new token using the Refresh token. Refer to the earlier section for the API endpoint details to refresh the token.

  1. After the trigger is added, add the SharePoint connector to get values of the Refresh Token, Client Id, Client Sercret etc
  2. Initialize variables to store the values retrieved from the SharePoint list
  3. Add a Switch control to store the values on the variable.
  1. Add a HTTP action to refresh the token as shown below
  1. Add the JSON parse action to get the new token values including the new Refresh Token. Once the refresh token is used, it cannot be used again.
  1. After getting the new values, update the access token & Refresh token in the SharePoint list.
  2. The package of this cloud flow can be downloaded from here.

Turn On/Off from Power Automate or Power Apps:

To turn on/off or set different colours of the light from Power Automate or Power Apps, create a Flow with HTTP action & call the API given in the above section. To call the flow in Power Apps, use the Power Apps trigger or use a custom connector.

Control Lights from a .Net application:

Find code below to turn on/off light from a .NET application

private static async Task<string> TurnOnPhilipsHue(string accessTokenPhilipsHue, string userNamePhilipsHue, string lightNoPhilipsHue)
	string requestUrl = "" + userNamePhilipsHue + "/lights/"+ lightNoPhilipsHue + "/state";
	using var client = new HttpClient();

	var payload = "{\"on\": true,\"bri\": 102}";
	client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessTokenPhilipsHue);
	var requestData = new StringContent(payload, Encoding.UTF8, "application/json");
	var response = await client.PutAsync(String.Format(requestUrl), requestData);
	var result = await response.Content.ReadAsStringAsync();
	return result;

There is also SDK for C#, do look at it on this url for more details.


I have used this light to build a Microsoft Teams status light, will post the link as soon as it is available. Hope you have found this informational & thanks for reading. If you are visiting my blog for the first time, please do look at my other blogposts.

How to invite external users to a SharePoint site or Microsoft Team using Power Automate and Graph API

SharePoint and Microsoft teams services in Microsoft 365 makes it easier to share content or collaborate with external users who is outside your organization. A guest or external user is someone who do not have a school or work account with your organization, they can be your partner, vendor, customer etc. In this article let us see how to build a self-registration experience for external users with the help of Microsoft Forms & Power Automate to onboard them to a

  • SharePoint online site
  • Microsoft Team

Microsoft Form to collect details from External User:

To start building this experience, create a Microsoft form with the setting Anyone can respond and with fields (Name, Email address etc) to collect information from the external user to send invitation.

Azure Active Directory Application registration:

The next step after creating the form is to register an application in Azure AD with Microsoft graph API permission to send invitation to external user. After the app is registered obtain the client id, client secret & tenant id to be used in the Power Automate flow further down this article to generate the JSON webtoken to access Microsoft Graph API for sending invitation. Find below screenshot with the permission User.Invite.All added to the app. Keep in mind the permission requires Admin consent.

There is also delegated permission available for User.Invite.All.

Onboard External users to a SharePoint online site:

Once the Microsoft form is ready, we can start building the Power Automate flow which can send the email invitation to the external user and for granting access to the SharePoint site. The external sharing features of SharePoint Online enables users in your organization share content with people outside the organization. There is no limit to the number of guests you can invite to SharePoint sites as per this SharePoint online limits documentation. Find below steps to create the Power Automate flow with a custom approval on a Microsoft Team

Power Automate Flow:

Create an Automated flow with the trigger When a new response is submitted with the above form name selected on the dropdown and then add the action Get response details with the Response Id selected from the dynamic content for the trigger to get the form details submitted in the Microsoft form by the external user. Find screenshot below

Adaptive card for Teams Approval:

For the Approval in Microsoft Teams, I have used a custom card created from the Adaptive card designer with elements ColumnSet, TextBlock to display information submitted in the form & action button Approve and Reject to take further action by a Microsoft teams user to proceed with Invitation for the Guest account creation. Find screenshot below from the adaptive card designer

  1. After the card is designed, copy the card payload from the designer and go to the flow and then add the action Post adaptive card and wait for a response and make appropriate selection on the available fields as shown below
    • Post as: Flow bot
    • Post in: Channel
    • Message: Payload copied from designer. Replace the fields for usrName & userEmail selected from the dynamic content from the outputs of the action Get response details. The created on textBlock element has the flow expression formatDateTime(utcNow(),’g’) to display the current datetime information on the card.
  • Update Message: Custom message which appear after an action taken in Microsoft Teams
  • Team: Select the Team where you would like to post the card
  • Channel: Select the channel from the Microsoft Team where you would like to have the approval adaptive card posted

Card payload:

    "type": "AdaptiveCard",
    "body": [
            "type": "TextBlock",
            "weight": "Bolder",
            "text": "Approval for adding the External User",
            "wrap": true
            "type": "TextBlock",
            "spacing": "None",
            "text": "Created Add flow expression to get current date",
            "isSubtle": true,
            "wrap": true
            "type": "ColumnSet",
            "columns": [
                    "type": "Column",
                    "items": [
                            "type": "TextBlock",
                            "text": "Name:",
                            "wrap": true,
                            "size": "Medium",
                            "weight": "Bolder"
                            "type": "TextBlock",
                            "text": "Email:",
                            "wrap": true,
                            "weight": "Bolder",
                            "size": "Medium"
                    "width": "stretch"
                    "type": "Column",
                    "width": "stretch",
                    "items": [
                            "type": "TextBlock",
                            "text": "usrName-Replace it from Microsoft Form",
                            "wrap": true
                            "type": "TextBlock",
                            "text": "userEmail-Replace it from Microsoft Form ",
                            "wrap": true
    "actions": [
            "type": "Action.Submit",
            "title": "Approve",
            "id": "btnApprove"
            "type": "Action.Submit",
            "title": "Reject",
            "id": "btnReject"
    "$schema": "",
    "version": "1.0"
  1. The above adaptive card is used to get approval from the Organization teams user based on the information submitted by the external user in the Microsoft form to proceed with the next steps for sending the guest account invite. Now we will have to identify if the user has clicked the button Approve or Reject. This information can be easily obtained from the Outputs of the action.

Note: Adaptive card can also be sent using a Microsoft Graph API with the card payload in Attachments field

Adaptive card for Teams – Dynamic content Missing:

As of the time I am writing this article there is an issue in getting the output as dynamic content for the Post adaptive card and wait for a response action if there is dynamic content added on the JSON Payload (Name, Email from Forms). The fix is to run the flow till the post adaptive card action and take an action on Microsoft teams by clicking either Approve or Reject and then go to the Flow run from the history as shown below

From the above screenshot, we can see if the user has clicked the Approve or Reject button from the field submitActionId. To get this value in Flow, use the expression




Spaces in the name of the action is replaced with underscore.

To get the userPrincipalName, the expression is




To get the submitActionId, enter the expression outputs(‘Post_adaptive_card_and_wait_for_a_response’).body.submitActionId in the compose action, then add a condition control to decide action based on users approval

I have observed this issue occurs in other team’s adaptive card actions as well, the above fix should work. Now we can implement the logic to send the Guest Invitation using Microsoft Graph API. To send the invite, we will use the Azure AD application registered above.

Generate JSON Web token to Access Graph API:

Be ready with the ClientId, Client Secret and Tenant Id collected from the AD app registration you have done initially. The only authentication flow to generate a access token for application permissions is Client credentials.

To generate a token

  1. Store the Client Secret on a String variable or a compose action
  2. Make a HTTP request using the HTTP connector with the following details. Make sure to replace the string for tenantId, azureAdAppclientId and azureAdAppclientSecret

Add a HTTP connector action to the flow for making a POST request per the following information



Headers: Content-Type: application/x-www-form-urlencoded



For the client secret make sure to URL encode using the expression encodeUriComponent(variables(‘clientSecret’)) else the request may fail due to the presence of special characters.

In the above screen, I have added a compose action to store the SharePoint site address to be used for granting the external user access to. To extract the token from the above request, add the parse JSON action with Content from the HTTP request body and the following schema

    "type": "object",
    "properties": {
        "token_type": {
            "type": "string"
        "scope": {
            "type": "string"
        "expires_in": {
            "type": "integer"
        "ext_expires_in": {
            "type": "integer"
        "access_token": {
            "type": "string"
        "refresh_token": {
            "type": "string"

Include the access token when calling the Microsoft Graph API in the Headers section or raw as shown in the next section.

Send Invitation using Microsoft Graph API:

Before sending the invitation, validate if the user already exists in your organization AD tenant by using the email address of the external user with the help of the action Search for users as shown below

If there is null response for the action Search for users, then the user does not exist. This can be calculated using the expression length and by passing the value as a parameter, if it is equals zero then the external user does not exist. If the user already exists, we can directly proceed to granting the external user access to SharePoint.

Graph API to check if a guest user already exists:$filter=UserType eq ‘Guest’&$filter=mail eq’


Find below the Graph API endpoint http request details to invite the external user

Method: POST


Request Body:

  "invitedUserDisplayName": "External User Name",
  "invitedUserEmailAddress": "External User Email Address",
  "sendInvitationMessage": true,
  "inviteRedirectUrl": "SharePoint site URL or any URL",
  "invitedUserMessageInfo": {
    "messageLanguage": "en-US",
    "customizedMessageBody": "Welcome to the M365PAL SharePoint site! Click the link below and sign in."

In HTTP request body, use the dynamic content of the form to populate the fields invitedUserDisplayName & Emailaddress. The invite redirectUri is the output of the compose action which has the SharePoint site url. I have added a delay of one minute before granting access to SharePoint site for the external user, this step is to make sure there is an entry in Azure AD for the external user/guest account.

Custom connector can be used for calling the Graph API for sending invitations instead of using HTTP connector, you can refer to the post Call Microsoft Graph API in Power Apps and Power Automate using a Custom connector for detailed instructions.

Grant Access to SharePoint site for the external user:

As soon as the guest account invite is sent from the above Microsoft graph API request HTTP action, it is time to grant access to the SharePoint site for the external user. There is a SharePoint REST API endpoint to add a user to a SharePoint group (Owners, Member, Visitors), find below the request details

Request URL: _api/web/sitegroups/GetById(groupId)/users

For the groupId to the corresponding SharePoint group, refer to the following table

SharePoint GroupGroupId


Key: accept value: application/json;odata.metadata=none

Key: content-type value: application/json



For the external user, the email address used to send the invite works.

Go back to the flow and add the action Send an HTTP request to SharePoint to call the above REST api. Find below the screenshot of the action

The above action uses delegated permission, the user of the connection should have access to the SharePoint site. As of now, there is no Graph API for adding the user to a SharePoint group but you can register an app in Active directory and add permission for SharePoint to call the above REST API. Refer to the documentation Granting access via Azure AD App-Only for calling the REST API using the registered AD app.

Testing the flow:

The whole flow can now be tested by submitting the form which sends the adaptive card on Teams first as shown below

After the card is approved, the invite is sent to the external user. After the external user accepts the invite, the user should be automatically redirected to the SharePoint site with the appropriate access. The access to the SharePoint site for the external user can be validated by the checking the membership of the SharePoint group in the site even before the user accepts the invitation. The site members can also be validated by accessing the URL for All users list:

This approach of granting access to SharePoint site for external user can be applied to internal users by turning off the access requests.

Limit External Sharing by domain:

The external sharing on SharePoint can be restricted based on domain of the external user. To enable the setting login into the SharePoint admin center > Policies > Sharing > Enable the checkbox Limit external sharing by domain > Add domain

Onboard External users to a Microsoft Team:

To onboard the external user to a Microsoft Team, the only change to the above flow is, instead of adding the user to the SharePoint group the user must be added as a Member to the Microsoft 365 group connected to the Microsoft Teams. The graph API to add a member to a Microsoft Team is

Request Type: POST

Request URL:{team-id}/members

The team-id is the Microsoft 365 group object Id, as there is always a Microsoft 365 group connected to a Microsoft Team.


    "@odata.type": "#microsoft.graph.aadUserConversationMember",
    "roles": ["owner"],
    "user@odata.bind": "')"

The expression to get the user object Id of the external user as per the below screenshot is

outputs(‘HTTP-SendGuestInvitation’).body.invitedUser.Id The expression can be used in a compose action to get the Object Id of the external user which can be used in the Graph API request to add the member to a Team. HTTP-SendGuestInvitation is the name of the HTTP Action.

Permission for the Azure AD App to add a member to a Microsoft Team:

The application permission Group.ReadWrite.All has to be added on the Azure AD app, if you are going to be using the same JSON webtoken generated above. There is delegated permission as well for adding members.

I recommend you read the following documentation from Microsoft for External sharing

Summary: With this, the Power Automate flow should send the invitation as shown below to the external user.

If it is for a Microsoft Team, the external user should be licensed for teams service to open it on their teams client. The same flow can be also configured for Microsoft 365 group. If you are visiting my blog for the first time, please do look at my other blogposts.

How to use Microsoft graph SharePoint Sites.Selected application permission in a Azure AD application for more granular control

As per this announcement made on Feb 2021, Microsoft graph now provides option to have granular permissions level using Sites.Selected application permission for the AD application instead of granting permission for all the sites in the tenant. The permission Sites.Selected does not provide access to any SharePoint site collections for the application unless the AD application has been assigned with permission roles read or write by an Admin. On this post let us see how to grant a site permission (Read or Write) to an AD Application with Sites.Selected permission by using postman client. As of the time I am writing this post there is no user interface to assign permissions to specific site collections for the application.


  1. Register Azure AD Application (APP 1) in Azure AD Portal with the following permissions
    • Sites.Selected (Admin Consented)
  2. Another AD Application (APP 2) with following permission only for the admins to assign selected roles to the above App
    • Sites.FullControl.All (Admin Consented)

App Registration:

Start with registering the above said two Azure AD applications

APP 1:

Register an Azure AD application with the following permission

APP 2 (Admin App):

Another app for admins for granting roles to APP 1

Grant permission role to the SharePoint site for the Azure AD Application:

This step is grant permission for the Azure AD application with Sites.Selected application permission to a given site collection. Perform the following steps to grant the role (Read/Write or Read and Write) to the AD app (APP 1)

  1. Gather the Client ID, Tenant ID and Client secret of the admin app
  2. In PostMan, make a HTTP request to generate the access token for the admin app – APP 2

Request Method: POST

Request URL:

Request Header:

Key: Content-Type

Value: application/x-www-form-urlencoded

Request Body:

grant_type: client_credentials


client_id: adminappclientid

client_secret: adminappclientsecret

  1. Copy the access_token to be used for granting roles.
  2. Get the Client ID of the Azure AD Application – APP 1 with Sites.Selected permission
  3. Decide on the Role (Read or Write) for the granting the Site specific role for the APP 1 with Sites.Selected permission.
  4. Get the SiteId of the SharePoint site to be assigned permissions for the application (App 1). An easy way to get the siteId is by viewing the page source from the browser with the site open.
  5. In PostMan, make a HTTP request to grant the site role to the APP 1. Replace the siteId with the actual siteId which will be a guid

Request Method: POST

Request URL:

Request Header:

Key: Content-Type

Value: application/json

Request Body: raw

Replace the id with APP 1 client id and the display name of the APP 1


  "roles": ["write"],

  "grantedToIdentities": [{

    "application": {

      "id": "xxxxxx-APP1GUID-4ad9-xxxx-4d36e68b0454",

      "displayName": "AppNamewithSelectedPermissions-App1"



  1. Paste the access token on the token box as shown below with Authorization type selected as Bearer Token
  1. Send the request for granting the role for APP 1. After the request is made the APP 1 with the Sites.Selected permission has access to the site with write role we have granted to. The same way you can assign app access to multiple SharePoint sites.

Grant the Role using PnP PowerShell:

There is a PnP PowerShell cmdlet to grant access to SharePoint site for the registered AD application with Sites.Selected permission. The command to grant permission can be executed by the Site Collection administrator after creating a connection to the site

Connect-PnPOnline -Interactive

You will be prompted to enter credentials including the second factor. After the connection is created, enter the following command to grant Write permission to the AD App

Grant-PnPAzureADAppSitePermission -AppId 'AzureAppIdwithSitesdotselectedpermission' -DisplayName 'App Name here' -Site '' -Permissions Write

To install PnP PowerShell module on the local workstation, enter the following command

Install-Module -Name PnP.PowerShell

There is also a PnP cmdlet to register an AD app in the Azure Active directory.

Grant the Role by an Admin using the Graph Explorer tool:

Role can also be assigned by an admin with out having the admin AD app (APP 2) using the graph explorer tool. This can be done only by an Admin

If there is any error related to permissions, make sure the admin consents to Sites.FullControl.All for the Graph tool. There is also an SPFx community webpart developed by a community member with User Interface for this operation


Assign permission role programmatically:

Summary: On this post we have seen how to grant access to Azure AD which has the Sites.Selected permission. You can also grant permission/role to an app with sites.selected permission programmatically. Hope you have found this informational & thanks for reading. If you are visiting my blog for the first time, please do take a look at my other blogposts.

Hosting static HTML content in SharePoint Online site & Azure

The SharePoint Online experience which you get by default for all the sites you create in the tenant is modern by default. The site pages you create in the modern experience are fast, easy to author and support rich multimedia content. The pages look great on any experience i.e. mobiles, browser, SharePoint App. If you wanted to host static HTML content with JavaScript, CSS, BootStrap on a SharePoint Online site it is not feasible though it was easily doable with Classic SharePoint site. The reason is by default you are not allowed to run custom scripts to change the look & feel & behaviour of the sites for security reason in a Modern SharePoint Online site. But we have control to manage this setting at different levels

  1. Organizational Level
  2. Site Level

On this blog post let’s see how to host static content (HTML, JS, CSS, Images et) by updating the site scripts settings at the site level. At the end I write some options to host Static content in Azure.


  1. Modern SharePoint Communication Site
  2. SharePoint Online Tenant Admin access for executing few PowerShell commands
  3. HTML Content
  4. Access to Azure Subscription as a Contributor to test static content hosting in Azure

Hosting Static content on a SharePoint Online Site:

For sample HTML content I’ve downloaded from the following Azure Sample GitHub repo

Step 1:

Connect a SharePoint Online administrator to a SharePoint Online connection. This cmdlet must run before any other SharePoint Online cmdlets can run

Connect-SPOService -Url

Step 2:

Run a Power shell command to disable the property DenyAddAndCustomizePages at the site level by running the following command

Set-SPOsite -DenyAddAndCustomizePages 0

Step 3:

Verify if DenyAddAndCustomizePages is Disabled. To check this the property value run the following command

Get-SPOSite -Identity -Detailed | select DenyAddAndCustomizePages

Step 4:

Be ready with the HTML sample. I’ve downloaded static content from the Azure HTML Sample github repo which has

  • HTML
  • CSS
  • JavaScript

If there is any file with HTML extension, rename the extension to .aspx. On this sample there was 1 HTML file by the name index.html, I’ve renamed the file index.html to index.aspx

Step 5:

Open the SharePoint Online Communication site in the browser & navigate to the Document library. I’ve chosen the default document library (Shared Documents) for the storing the HTML, you can also create a custom document library, site assets library.

Upload the folder which has the .HTML file renamed to .aspx and the supporting files (JS, Images, CSS etc)

After the upload

Click the index.aspx file, it should render the file with HTML, CSS, JS etc as shown below

The URL of the HTML page will be in the following structure for the index.aspx file Documents/HTML_sample_for_Azure_App_Service/index.aspx

In the document library if you have a HTML file converted to ASPX before executing the command, it may not work. To make it work delete the ASPX file and upload it again to the document library


Step 6:

You can now Enable the property DenyAddAndCustomizePages by executing the following SharePoint Online PowerShell cmdlet

Set-SPOsite -DenyAddAndCustomizePages 1

If you wanted to add another HTML file after the above command, you will have to disable the property DenyAddAndCustomizePages before adding the HTML file. I’ve shown you how to host static HTML on SharePoint Online site which will not cost you anything provided there is Microsoft 365 license. If you need additional features like Custom domain, anonymous access, deployments etc you can do so with Azure.

Embed the Static HTML Page in a SharePoint page:

To embed this on a SharePoint Page, add the Embed webpart on the page and paste the above link on the Webpart property pane for Website address or embed code as shown below

Static Content in Azure:

There are couple of options in Azure to host your HTML as shown below

  1. Azure App service
    • You can create an App service in Azure to host your static HTML. There is Microsoft documentation with detailed instruction to set this up. You can lot of options with App service like Auto scaling, Custom domain, Anonymous access, auto deployments etc. There is also a Free pricing tier F1 for hosting your content.
  2. Azure Static Webapps
    • As of now the service is in Preview mode which automatically builds and deploys full stack webapps to Azure from Github repository. During preview, its free of cost. I’ve recently tested this, if you wanted to try go through this documentation.
    • VS Code extension for Static Webapps
    • You can also serve dynamic content with Azure functions integration.
  3. Azure Storage
    • This service also has capability to serve static content (HTML, CSS, JS & image) from the blob container. To know more, check this documentation from Microsoft.

Summary: On this post we have seen options to host static content in SharePoint Online site & Azure. Based on your requirement (Anonymous access, custom domain, cost etc) you can choose one from the options given above. Hope you have found this informational & helpful in some way. If there is some other option to host static content, please let me know on the comment section below