How to get new team creation in MS Teams using MS Graph Notification API?


A colleague asked me how to get a notification when anyone creates a Team on MS Teams? The answer is pretty simple you would use the MS Graph Notification API. There is an MS Learn session here.

What I will write in this blog post is to answer the above question using Power Automate. I will create two applications.

  1. One to listen to the notification sent for the create or change of team, aka Web Hooks.
  2. One for subscribing to the notification API. For simplicity, I will make use of the Graph Explorer tool for it.


  1. You will need Power Automate Premium license for creating HTTP request trigger.
  2. You will need a Consent “Group.ReadWriteAll” permission for Graph Explorer.

Step by Step for Web Hook

Step # 1 First you will need an “When a HTTP request is received” trigger.

Please copy the ‘HTTP POST URL’ to a clipboard. (You will need this value later)

Step # 2

Create a condition for this WebHook to check whether there is any ‘queries’ parameter passed. If passed then read and send back the validationToken with 200 OK.

Check for following condition. Please put the '?' in the equation, it is important.

triggerOutputs()?['queries']                     is not equal to $null      AND 
triggerOutputs()?['queries']?['validationToken'] is not equal to $null      AND triggerOutputs()?['queries']?['validationToken'] contains        Validation

Step # 3

If the condition is success to send back the validationToken.

If condition is not successful that means the notification is received with the body.

For above Condition TRUE

This is a very IMPORTANT step, you must send the response back with 200 OK with body of the validationToken. Use the following expression to send the validationToken


For above condition FALSE

In the false condition, you should process the body value. The body value will have the notification information with the change Type and resources ID. Please note that there will not be additional data for the resource, if needed then you will have to write the code to get that information using the resource ID. Finally, you will need to send the 200 OK response with no body value acknowledging that you have received the notification no further notification will be sent.

Step By Step to Subscribe

Step # 1

To simplify this article I will use Graph Explorer to subscribe to the notification of the groups’ changes. It will require that Graph Explorer Tool has been consented to “Groups.ReadWrite.All” permission. If you do not consent the Graph Explorer will give you an error during the subscription.

changeType set to updated will receive notifications on the creation of a new group.

In Graph Explorer you will make a post request to the URI ‘’

## In the request body you would put the following JSON. 
## In the notificationUrl put the above copies URL from Power Automate Trigger.
## Change the expiration date according to your time.
    "changeType": "updated,deleted",
    "notificationUrl": "[Paste Text from Step 1 of 'Step by Step for Web Hook'",
    "resource": "/groups",
    "expirationDateTime": "2021-04-10T00:00:00Z"

To consent for the Group.ReadWrite.All, in GE you would click on “Modify permissions” -> “Open the permission panel” -> Select Group -> Select “Group.ReadWrite.All”. Finally, you will need to click on the Consent button. Which will pop up a consent window, select OK. This action will create an Azure AD app on your tenant with the consented permission.

Finally you should see the following in the Power Automate Run mode when you subscribe.

The condition expression will be true. When it is true send the response back with the validationToken as a body.


The above article is an attempt to simplify to answer one question. A similar approach can be used for other supported notification types resources. You will need the consent to correct permissions.

Posted in MS Graph | Leave a comment

How to make SharePoint REST API calls in PowerShell using Add-ins App?


The following links will guide you to create SharePoint Add-ins App with the required permissions. For security reasons, always have least permission access strategy to provide permissions to your app. Only provide permission access what your app intends to do, start with List, Subwebs, Webs, Site Collection and so on.

Add-in permissions in SharePoint

SharePoint Add-In — Permission XML cheat sheet

The following three URLs will be handy, the first one is to register a new app, second is to set the permissions for the app and third one is to list apps you or others have previously created.

  1. https:// [Your SharePoint Site URL]/_layouts/15/AppRegNew.aspx
  2. https:// [Your SharePoint Site URL]/_layouts/15/AppInv.aspx
  3. https:// [Your SharePoint Site URL]/_layouts/15/AppPrincipals.aspx

Step By Step

Step # 1 Once you have created the Client ID and Client Secret you want to create PowerShell Function as defined below. The first code block is to set required variables and second code block is to define a function to get an access token for the app.

# Add-type is required for the use of System.Web.HttpUtility
Add-Type -AssemblyName System.Web

$client_Id            = '[TODO SET CLIENT ID]'
$client_secrect       = '[TODO SET THE SECRET]'
# The secret should be url encoded.
$client_secrect_enc   = [System.Web.HttpUtility]::UrlEncode($client_secrect)
$TenantID             = '[TODO SET YOUR TENANT ID]'
$TenantName           = '[TODO SET YOUR TENANT NAME]'
$siteName             = "[TODO SET YOUT SITE RELATIVE NAME]"

# This function is to get an access token for the app.
function Get-AccessToken()

    # form an url with your tenant ID
    $url = $("{0}/tokens/OAuth/2" -f $TenantID)
    $headers = @{
        'Content-Type' = 'application/x-www-form-urlencoded’
        'Accept' = '*/*'
    #create a body
    $body = $("grant_type=client_credentials&client_id={0}%40{1}&client_secret={2}&resource=00000003-0000-0ff1-ce00-000000000000%2F{3}{4}" -f $client_Id,$TenantID,$client_secrect_enc,$TenantName,$TenantID)
    # make a call
    $item = Invoke-WebRequest -Method POST -Uri $url -Headers $headers -Body $body -UseBasicParsing

    $res = ConvertFrom-Json $item
    return $res
// %40 is @ and %2F is /

Step # 2 Now the next step is to use the above function to get an access token.

function get-top-100-items()

    # Get an access Token
    $response = Get-AccessToken

# form the REST URL to make a call to get items from a list.
$url=$("https://{0}{1}/_api/lists/getbytitle('DEMOList')/items" -f $TenantName, $siteName)

#set the header pass the token type and access token.
    $headers = @{
        'Authorization' = $(“{0} {1}” -f $response.token_type,$response.access_token)
        'Accept' = 'application/json; odata=verbose'

# make a REST call with the url and header
    $item = Invoke-WebRequest -Method GET -Uri $url -Headers $headers -UseBasicParsing

    # The following is to error
    # ConvertFrom-json : Cannot convert the JSON string because a dictionary that 
    # was converted from the string contains the duplicated keys 'Id' and 'ID'.
    $strContent = $item.Content -creplace '"Id":','"Id-minus":'

    $items = ConvertFrom-Json $strContent

    return $items

function main()

    $AllItems = get-top-100-items

    $count = $AllItems.d.results.Count

    for ($i = 0; $i -le $count; $i++)
        $Title  = $AllItems.d.results[$i].Title.Trim()
        $rowID = $AllItems.d.results[$i].ID



The above steps provided a way to make a SharePoint REST call. This is a sample ways to make a call in PowerShell you can replicate same method in any other language.

Keep the following SharePoint REST Wall Poster as a reference.

SharePoint 2013 REST Syntax (wall posters)

Posted in SharePoint | Leave a comment

How to split large string with emails in an array?


The following was the user requirement.

The question was the user had the weird string stored in the Multi People Picker Field.


If you look closely at the sample string the “i:0#|membership|” is prefixed before all the emails. The question is how to get just emails with the array of emails. For a developer, it may not be difficult. But for a no-code citizen developer, it will be tricky. This blog post will explain step by step how to extract emails by using two string functions “concat” and “split”.

For other function reference, please book mark url

Step by Step Solution

Step # 1 Create a manually triggered flow with a Var1 variable.

Step # 2 Now we will add compose to split the string by ‘;’ (semicolon) character.

split(variables('Var1'), ';')

The above expression will provide the following output.


Step # 3 Iterate over the above compose output and split the each item in array on a pipe character ‘|’.

split ( item(), '|') [ 2 ]

The above function will split on a pipe character for each items in the array.
e.g. for "i:0#|membership|" the out put will be
just email i.e. "".

First the split will create and array as
after that we are selecting the third element of the array. Note: the array is zero indexed so the third element will be 2.

NOTE: The final Compose “FinalArrayOfEmailsCompose” outside of the Apply each is a trick for collecting all values in the array.

The trick is make sure you are using inner loop’s compose as an input to it. Like following


So when workflow runs the output of the final compose will look like the following.


The final output is converted to required array with emails. Also we looked at the technique of Compose outside of Apply Each and collecting Compose values defined in the loop.

Posted in Power Automate | Leave a comment

How to create HTML table for Get Items in Power Automate?


A question from user is that how to send multiple pending items from a list in an HTML table format.

The desired results in email is the following with ID, Title and Clickable link item.

The email from the Power Automate Flow.

Step by Step Solution

To make the flow simple I will just focus on how to get the above HTML table after getting items from the list let’s make a Manually triggered flow.

Step # 1 Create a manually triggered flow get all items from the FAQ list.

In your case you may have some more filter to get the items from the list, but for simplicity I am getting all items from an FAQ list.

Get items from an FAQ list

Step # 2 Use Create HTML table action to create table.

Map ID, Title and Link columns. See below
ID is mapped => item()?['ID']
Title is mapped to => item()?['Title']
Link is mapped to => concat('<a href="',item()?['{Link}'],'">Click Here</a>') 

# note the link will generate string like
<a href="https://blah blah blah">Click Here</a>

Step # 3 Now is the hard part, the expression to replace encoded html tags.

This is a required step, the output of the Create HTML Table does not put the HTML element as tags instead it put as encoded strings.

Compose to replace &lt, &gt;, &qout; &amp; with < > ” & respectively. Also add table border and padding.
# if you simply want to copy the expression use the following, but see below 
# for the explanation of replace.

replace(replace(replace(replace(replace(body('Create_HTML_table'), '&lt;', '<'), '&gt;', '>'),'&quot;','"'),'&amp;','&'),'<table>','<table border="1" padding="5">')

# Note the following is the breakdown of the above expression, 
# there are five replace expressions for '&lt;', '&lt;', '&quot;', '&amp;' and '<table>'.

        '&gt;' '>'
  '<table border="1" padding="5">'

Step 4 Finally use the output of the Compose to send and email.

Send an email using the output of the compose.


The Compose output will have properly formatted table which can be sent in an email body.

My inspiration is from the following awesome article.

Formatting HTML Tables in Flow | April Dunnam – SharePoint Siren

Posted in Uncategorized | Leave a comment

How to develop SPFX using Docker Container?


Wouldn’t it be nice if you don’t have to install required SPFX tools to do the development?

Yes, answer is to use Docker. The Docker provides a container with required software pre installed. To use the container you should have an image.

Think of Docker Image as a Class and Docker Container is like objects. The images are template to run the container(s).

Step by Step Solution

The prerequisite is that you will need to install the Docker desktop on your host machine. To install Docker desktop go here.

Step # 1 Run the docker to launch container.

# use the following command in the PowerShell command prompt.
docker run -it --rm --name spfx-dev -v ${PWD}:/usr/app/spfx -p 5432:5432 -p 4321:4321 -p 35729:35729 dannyjessee/spfx
-it–interactive Keep STDIN open even if not attached
–rmAutomatically remove the container when it exits
–nameAssign a name to the container
-vBind mount a volume
-pPublish a container’s port(s) to the host
Map host ports 5432, 4321 & 35729 to the container
dannyjessee/spfxThe image name
Docker run command options

Step # 2 Check the version of the installed software on the container.

npm ls -g --depth=0

Step # 3 Create SPFX using Yo

Create the SPFX Webpart

Step # 4 Some changes are required in the created solution to work with Docker.

Changes for SharePoint Framework v1.11 project to support running the local workbench from within a Docker container. The following files needs the change.

config\serve.json, add below line 3:

"hostname": ""

config\write-manifest.json, add below line 4:

"debugBasePath": "https://localhost:4321"

node_modules\@microsoft\sp-build-web\lib\SPWebBuildRig.js, replace lines 96-98 with:

if (!spBuildCoreTasks.writeManifests.taskConfig.debugBasePath) {
         debugBasePath: ${serve.taskConfig.https ? 'https' : 'http'}://${serve.taskConfig.hostname}:${serve.taskConfig.port}/

Step # 5 Build and debug

run gulp serve

Posted in Docker | Leave a comment

How to export Data Loss Prevention (DLP) rule package for tenant?


I looked at the custom DLP config file in XML. This will allow to create Custom DLP rule. But I wanted to see if I can export all existing out of the box rules file in an XML. This will allow to study and create a custom new DLP Policy.

Step by step solution

Step # 1 Install and import the ExchangeOnlineManagement module in PowerShell

PS C:\DLPRules> Install-Module ExchangeOnlineManagement
PS C:\DLPRules> Import-Module ExchangeOnlineManagement

Step # 2 Connect to the portal with global admin user using Connect-IPPSSession

PS C:\DLPRules> Connect-IPPSSession
WARNING: Your connection has been redirected to the following URI:                                                      
";PSVersion=5.1.19 041.610"                                                                                                                PS C:\DLPRules> Get-DlpSensitiveInformationTypeRulePackage                                                              

Step # 3 List the Rule pack of the tenant

PS C:\DLPRules> Get-DlpSensitiveInformationTypeRulePackage
 Invariant Name         Localized Name         Publisher             Encrypted 
 --------------         --------------         ---------             --------- 
 Microsoft Rule Package Microsoft Rule Package Microsoft Corporation False     

Step # 4 Using the above localized name “Microsoft Rule Pacage” get package info

PS C:\DLPRules> $rulepak = Get-DlpSensitiveInformationTypeRulePackage -Identity "Microsoft Rule Package"

Step # 5 Now export the package info to an XML file

PS C:\DLPRules> Set-Content -Path "C:\DLPRules\ExportedRulePackage.xml" -Encoding Byte -Value $rulepak.SerializedClassificationRuleCollection

The file should be created now like the following.


PS C:\DLPRules> dir
 Directory: C:\DLPRules
 Mode                 LastWriteTime         Length Name
 ----                 -------------         ------ ----
 -a----         12/7/2020   2:23 PM        2041460 ExportedRulePackage.xml
 PS C:\DLPRules>
Posted in DLP | Leave a comment

How to send approval requests to Distributed List (DL) Group in Power Automate


The Microsoft Flow Approvals connector does not support sending approval requests to groups today or distributed groups.

To demonstrate the issue I have a sample distributed list (DL) group ‘SomeO365DLGroup’.

The DL group has the following members.

Members of the DL group

Created a sample manually triggered flow to send and approval with the DL ‘’. I got the following error.

  "error": {
    "code": "InvalidApprovalCreateRequestAssignedToNoValidUsers",
    "message": "Required field 'assignedTo' contained no valid users in 
the organization"
Error in the flow

Step by Step Solution

There is an alternative approach, first to get list of members email from the DL group. We will use the “Office 365 Groups” connector with “List group members” action. The action requires to use the group ID.

Step # 1 : Using Azure AD portal get the group id of the distributed list.

To get group id of the distributed list

Step # 2 : Create a Manually trigger with a EmailArray variable as Array datatype.

Step # 3 : In the manually triggered Power Automate make a call to the ‘List group members’

‘List group members’ action.
The output of the above action is.
    "@odata.type": "#microsoft.graph.user",
    "id": "17d7b3e9-7e7c-46e5-b16f-2baef2e6cd46",
    "businessPhones": [
      "+1 732 555 0102"
    "displayName": "Jordan Miller",
    "givenName": "Jordan",
    "jobTitle": "Auditor",
    "mail": "",
    "officeLocation": "19/3123",
    "surname": "Miller",
    "userPrincipalName": ""
   ... other objects are removed brevity

Step # 4 : Loop through the output of the above action to get the mail of the each member. Add the mail address in the EmailArray variable.

Loop through the output to get mail address

Step # 5: Finally use the EmailArray variable to create a string with semicolon delimited string.

Use join expression to get the “Email addresses, separated by a semicolon (;)”

Step # 6: Use the output of the above step as the Assigned To field.

Use the output of the Compose to the “Assigned to” field.


The alternate approach to get the list of emails to use in the Assigned to field resolved the issue of the distributed list group mentioned.

Posted in Power Automate | Leave a comment

SharePoint HTTP connector: Send a no-reply email in Power Automate Flow


There are many blog posts for sending no-reply email from Power Automate.

The question from the customer is how to create the JSON object body ‘dynamically’ to put in the “SharePoint HTTP connector”?

The following is the sample list with Subject, Body and TO (with multi-person) fields data. How to read this information and create the JSON body for the no reply email?

Sample list for sending and email using “SharePoint HTTP connector”
Note: This is the format of the JSON object you need to pass
Please note the To field is a JSON array.

  "properties": {
    "Subject": "This is a new request from test system.",
    "To": [
    "Body": "**removed for brevity***"
Note: In the above 'To' is a JSON array.

Step by Step Solution

This solution will required some basic understanding of the JSON object and JSON array.

We will make use of the setProperty expression to set the property of the JSON object.

IMPORTANT: The ‘Set Variable’ action does not allow self reference, in other words you can not do Index = Index + 1. See here for the details. The alternative approach is to use the Compose action to manipulate the variable value and then assign the output of the Compose in the Set Variable.

Step # 1 Define a manual trigger, two variables and a Get Item action.

JSON Object and JSON Array variables are defined.

Step # 2 Set the ‘Subject’ property to the ‘PropertiesObjectVar’ variable

Set the Subject Property using Compose action and use the Set Variable action
Note: First time 'PropertiesObjectVar' variable is an empty object.


Step # 3 Set the ‘To’ property to the ‘PropertiesObjectVar’ variable

Now there is a trick here, we need the JSON Array object. In the Apply Each action first get all values in the Array variable ‘ToFieldArrayVar’.

Apply Each action to extract Email and append to Array variable ‘ToFieldArrayVar’

Using the output of the array variable set this to the JSON object ‘PropertiesObjectVar’

Set the To property of the JSON Object
Note: The 'PropertiesObjectVar' variable is not with 'Subject'.
After the set Property it will have 'To' property


Note: The array variable is assigned to 'To' property.

Step #4 Set the ‘Body’ property to the ‘PropertiesObjectVar’ variable

Set the Body property for the JSON Object
Note: The 'PropertiesObjectVar' variable will have 'Subject' and 'To', the following call with add 'Body'


Step #5 Finally construct the Final Object as required for the no reply email.

A Compose action to create a final JSON object.
Note: setProperty trick is start with empty JSON object and add 'properties' property to it with a above constructed variable.

       json('{  }'), 

Step #5 Now use Send HTTP to send an email.

Note: Copy the following in the Uri section


Note: copy the following in the Headers section
   "Content-Type": "application/json;odata=nometadata",
   "Accept": "application/json;odata=nometadata"


Using the setProperty, Compose and some tricks this posts may help you with constructing the JSON Object dynamically.

FYI the list of properties for the EmailProperties.

Posted in Power Automate | Leave a comment

How to delete Recoverable Items folder of the mailbox?


This was a customer requirement, to delete a “Purge” folder using MS Graph API. There was no mention of purge folder when I checked mailFolder resource type documentation. The closest I found was ‘recoverableitemsdeletions’, I did not even know what ‘purge’ folder meant. So I took some help from a friend Boris Lokhvitsky (an Exchange SME).

Step By Step Solution

To protect from accidental or malicious deletion and to facilitate discovery efforts commonly undertaken before or during litigation or investigations, Exchange Server and Exchange Online use the Recoverable Items folder.

Each user mailbox is divided into two subtrees: 

  1. The IPM (interpersonal messaging) subtree
  2. The non-IPM subtree

The IPM tree is what user can see in Outlook, but the non-IPM can not be seen by the users.

The following few steps are needed to make the mailbox for a litigation hold. The EXO will create the non-IPM folders like ‘Purge’ folder and more. After that you will need to create Azure AD app with MS Graph permission “Mailbox.ReadWrite” to use in the PowerShell script.

Step # 1 Install and import the Exchange PowerShell module

# In PowerShell command prompt install and import the module.
 Install-module ExchangeOnlineManagement

 Import-module ExchangeOnlineManagement 

Step # 2 Connect to Exchange Online

 $userCred = Get-Credential

 Connect-ExchangeOnlie -Crendential $userCred -ShoProgress $true 

Step # 3 Set litigation hold on a mailbox

In this step run the following command for a specific mailbox to set a litigation hold.

            -LitigationHoldEnabled $true `
            -LitigationHoldDuration 2555 

Step # 4 Create an Azure AD app with “Mailbox.ReadWrite” MS Graph permission with admin consented. Please make a note of the Client ID and Client Secret to use in the next steps in PowerShell.

“Mailbox.ReadWrite” MS Graph permission with admin consented

Step # 5 Get a token from Azure AD

The following call with return an Access Token.

# make a call to Azure AD with Azure AD App in a body 
# body

Step # 5 MS Graph GET call using Bearer

 $headers = @{}
 $headers.Add("Authorization", $("{0} {1}" -f 
 $responseAuth.token_type, $responseAuth.access_token)){USER_UPN}/mailFolders   

The above script steps are located here for you to use.


The purge folder deletion is a tricky step. I hope that it is clarified with this blog post. If there is any comments or questions please post them here so I can improve this blog post.

Refer the following article for an additional details.

Clean up or delete items from the Recoverable Items folder

Posted in Exchange Online | Leave a comment

Part Two – Using Power Automate show the most recent comment from SharePoint text fields instead of “View Items”


As my previous blog post on the same topic, what if there is an existing list which has the multi text ‘Comments’ field.

How to take the last comment and copy in the ‘MostRecentComments’ field for all items in the existing list?

Step by Step Solution

Step # 1 – Create a Manually Trigger flow.

Step # 2 – First let’s get all items IDs (plus required fields) from the list using ‘Send an HTTP request to SharePoint’.

*** Uri ****

*** Headers ***
   "Accept": "application/json;odata=nometadata"

***** The output of the action will be an Object with an Array ***
  "value": [
      "Id": 5,
      "ID": 5
      "Id": 6,
      "ID": 6

Step # 3 Iterate over each array item and get the Comments field with “versions“.

Note: Apply each of the “value” property of the above step and it is an array.

**** Uri *** Note: we just need multi text Comments field and it's versions.


*** Input Headers ***
   "Accept": "application/json;odata=nometadata"

*** Output for each ID will be like following ***
Note: There will be nulls, we need to eliminate nulls in the next step.
  "value": [
      "Comments": null
      "Comments": "This is a test2"
      "Comments": "Lorem Ipsum ...."

Step # 4 Within the ‘Apply Each’ loop filter the null from the Comments array.

*** From ***
Note: we need to get the Value array

*** In the condition ***
Note: items is a special function to access each item.
** The output of the Filter will be with Comments with *no* null values 

Step # 5 Final step in the ‘Apply Each’ to update the list.

*** The MostRecentComments field will be set with the first value 
of the filtered array ***



The final result will be have last comment in the ‘MostRecentComments’ field. This blog post is a technique to update your all items in the existing list. Once you have done that you will not have to run this flow. From my previous blog post the item added and modified event will update the ‘MostRecentComments’ correctly.

Posted in Power Automate | Leave a comment