Vue normale

Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.
À partir d’avant-hierFlux principal

Microsoft Limits Graph API Requests for User Account Data

Old Limit with SignInActivity was 999 – New Limit for Azure AD Accounts is 120

Because it retrieves details of Azure AD accounts, the List Users API is one of the most heavily used of the Microsoft Graph APIs. It also underpins the Get-MgUser cmdlet from the Microsoft Graph PowerShell SDK. Microsoft generates the cmdlet from the API using a process called AutoRest, which means that changes made to the API show up soon afterward in the cmdlet.

I’ve documented some of the issues that developers must deal with when coding with the cmdlets from the Microsoft Graph PowerShell SDK. The cmdlets have been stable recently, which is a relief because tenants are migrating scripts from the Azure AD and MSOL modules. However, last week an issue erupted in a GitHub discussion that caused a lot of disruption.

In a nutshell, if you use List Users to fetch Azure AD accounts and include the SignInActivity property, the API limits the page size for results to 120 items. Calls made without specifying SignInActivity can set the page size to be anything up to 999 items.

An Unannounced Change

To help manage demand on the service, all Graph API requests limit the number of items that they return. To retrieve all matching items for a request, developers must fetch pages of results until nothing remains. When a developer knows that large numbers of items must be fetched, they often increase the page size to reduce the number of requests.

Microsoft didn’t say anything about the new restriction on requests that fetch Azure AD account data with sign-in activity. Developers only discovered the problem when programs and scripts failed. I first learned of the issue when some of the users of the Office 365 for IT Pros GitHub repository reported that a Graph request which included a $top query parameter to increase the page size to 999 items failed. For example:

$uri = "https://graph.microsoft.com/beta/users?`$select=displayName,userPrincipalName,mail,id,CreatedDateTime,signInActivity,UserType&`$top=999"
[array]$Data = Invoke-RestMethod -Method GET -Uri $Uri -ContentType "application/json" -Headers $Headers
Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
At line:1 char:16
+ ... ray]$Data = Invoke-RestMethod -Method GET -Uri $Uri -ContentType "app ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest)
   [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.I

As shown in Figure 2, testing with the Get-MgUser cmdlet revealed some more information in the error (“Cannot query data for more than 120 users at a time”). This was the first time I learned about a query limit:

Get-MgUser reports more useful error information

Cannot query data for more than 120 users at a time (SignInActivity)
Figure 2: Get-MgUser reports more useful error information

According to a response reported in the GitHub discussion, Microsoft support reported

The PG have confirmed that this endpoint will be transitioning from beta to General Availability (GA).

As part of this transition, changes to its behavior has been made, this includes not requesting more than 120 results per call. They recommend requesting less than 120 results per call, which can be done by setting the top parameter to, say 100.”

It’s likely that Microsoft made the change because retrieving sign-in activity data for Azure AD accounts is an expensive operation. Reducing the page size to 120 possibly makes it easier to process a request than if it asked for 999 items.

Beta Version of List Users Moving to Production

When the product group (PG) says that the endpoint is transitioning from beta to GA, it means that instead of needing to use https://graph.microsoft.com/beta/users to access sign-in activity, the data will be available through https://graph.microsoft.com/V1.0/users. If you use the Microsoft Graph PowerShell SDK, you won’t have to run the Select-MgProfile cmdlet to choose the beta endpoint. Moving the beta version of the API to the production endpoint is a good thing because there are many other account properties now only available through the beta endpoint (like license assignments).

If you use the Microsoft Graph PowerShell SDK, the Get-MgUser cmdlet is unaffected by the change if you specify the All parameter. This is because the cmdlet handles pagination internally and fetches all pages automatically without the need to specify a page size. For instance, this works:

$AccountProperties = @( ‘Id’, ‘DisplayName’, ‘SignInActivity’)
[array]$Users = Get-MgUser -All -Property $AccountProperties | Select-Object $AccountProperties

Moving to Production

Although it’s good that Microsoft is (slowly) moving the beta versions of the List Users API towards production, it’s a pity that they introduced a change that broke so many scripts and programs without any warning. At worse, this so exhibits a certain contempt for the developer community. At best, it’s a bad sign when communication with the developer community is not a priority. That’s just sad.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

The easiest way to test how your app handles API errors

The easiest way to test how your app handles API errors

How would you test this code?

async function getData() {
  try {
    const result = await fetch('https://contoso.com/api/data');
    if (result.ok) {
      return await result.json();
    }
  }
  catch (e) {
    // handle API errors here
  }
}

More specifically, how would you verify that the code in the catch clause, responsible for handling errors is working properly?

What if your API-handling code is more elaborate? What if you want to use rate limiting headers to back off and avoid getting throttled? And when you get throttled, you want to wait for the designated period and retry the request automatically? How do you verify that your code works correctly?

Using APIs is hard

It's hard to imagine an app that's not connected to an API these days. We use APIs for everything: from authentication, to data storage, to integrating AI. APIs are literally everywhere. And yet, it's surprising to see how hard it still is to build robust apps that use APIs.

The APIs we use in our apps are built by different vendors. Each API works differently than the other. But that's fine. Using their docs, we can integrate these APIs in our apps just fine. We can even go as far as to automate testing different scenarios relevant to our app. But not all of them.

While it's easy to get APIs to work, it's hard to break them. Yes, you can easily send an invalid request and see it respond with an error, but that's hardly something you'd see in production, unless you missed something fundamental. What is really hard about working with APIs is simulating different error states, like rate limits, throttling or servers getting overloaded.

What makes it even harder, is that vendors who publish APIs, often spend more time in their docs communicating how their APIs work rather than how their APIs behave when they fail. "It's a matter of perception" - you could say. But if you've worked with APIs a bit, you know that API failure is not a matter of "if" but "when". And having proper docs that describe erroneous behavior makes all the difference.

How developers handle API errors

Handling API errors is hard. Here's how developers typically deal with it.

Wrap the whole request in a try..catch

Probably the most frequently used solution out there is to wrap the whole web request in a try..catch clause. If calling an API fails for whatever reason, the app catches the error and shows a generic error. I bet you've seen an error similar to An error has occurred. Reload the page more than once. This is exactly, because developers used a generic try..catch statement.

Using this approach gives you an easy way out. After all, as a developer, you don't have to care about the exact API error. Something went wrong in an API you don't own, so you can't do nothing about it, right? So you show a generic error to the user, asking them to retry. What else can you do, right?

Use a dependency

There are dependencies that you can use in your project to help you handle API errors. Their functionality can be as simple as handling basic OData errors to handling throttling with exponential back offs. Thanks to these dependencies you can be smarter and automatically recover when possible without bother the user.

While it sounds great, what makes you so sure that the dependency will work properly with the APIs that you use in your app? Have you actually checked it? How would you though?

Make the API fail

When developers want to see how their app behaves when it gets throttled, they sometimes overload the API on purpose. They'll keep calling it until they exceed the quota or force a server error due to too high resource consumption.

It's far from perfect for both the API vendor and the developers. API vendor loses precious resources sometimes even leading to service outage, and developers incur additional costs. But how else would you verify how the app actually behaves when it gets one of these elusive errors?

Simulate API errors with mocks

More experienced developers, especially when they build a product, might go as far as mock APIs they use. Rather than calling the actual API, they simulate API responses in code what allows them to test different edge cases. This isn't trivial to do.

First, you need to have a thorough understanding of the API that you're using and its different behaviors. Can you get throttled? Does the API communicate rating limits? What other error states could the API communicate that you should consider? When do these errors occur and what is the shape of the error response that your app gets?

Once you know all of this, then you need to setup the necessary infrastructure to mock API calls and simulate the different errors. Simulating simple errors isn't hard. But it gets complicated when you get to simulating more complex behaviors like rate limiting that spans a series of requests.

And after you figured it all out, you also need to keep this in sync with the actual behaviors of the APIs that you use in your app.

Using APIs properly is hard

There's more to using APIs than meets the eye. A 200 OK response is just the tip of the iceberg. If you want to build robust apps that use APIs, you need to properly handle possible errors, and you have to verify that you're doing it correctly. This has nothing to do with your app's functionality, but what's the alternative? Hoping for the best while knowing that it's just a matter of time until your app breaks and loses someone's work?

See for yourself how your app will behave when APIs fail

The good news is, that there's a better way for you to see how your app will behave when the APIs that it uses fail. It allows you to see not just regular API failures, but rate limiting, throttling and any other type of error that an API might return. And you can do it without changing a single line of code in your app or standing up specific testing infrastructure and elaborate tests. Here's how.

Microsoft Graph Developer Proxy - an open-source proxy from Microsoft, allows you to simulate API errors. When you start it on your developer machine, it intercepts web requests from your app and returns simulated errors. You can use the Developer Proxy for simulating simple errors and more complex behaviors like throttling on any API. And because it's a proxy, you can use it with any type of app, build on any technology stack.

Check out this single-page app connected to Microsoft Graph that shows you information about people. At first, it seems to work just fine:

Web application showing photos and names of people

Let's see what happens, when one of the API calls would fail:

Empty page in a web browser. Next to it, a terminal window with Microsoft Graph Developer Proxy simulating API errors

Because the developer didn't implement any error handling, as soon as an API call failed, the whole app failed leaving the user with an empty screen. And remember what we discussed: it's just a matter of time before calling an API fails, so you better be prepared for it.

See how quickly we were able to find a flaw in this app? Notice, that we didn't have to change anything about the app or stand up any testing infrastructure. All we did was start the Developer Proxy and run the app. That's it.

Using the Developer Proxy, you'll find all kinds of issues related to using APIs in your apps:

  • How does your app behave when calling an API fails? Can it handle the error gracefully or will it crash losing the user's work?
  • Is the error message that you show to the user relevant to the type of error that occurred?
  • Do you even need to show an error message to the user or can you automatically recover, for example by retrying the failed request after some time?
  • When loading data takes longer than expected, is it clear to the user that your app is still working?
  • Could you cache data to use as fallback in case calling the API fails?

These are just some examples of insights about your app that you'll get when you test it with Microsoft Graph Developer Proxy.

Building robust apps that use APIs doesn't have to be hard. Microsoft Graph Developer Proxy allows you to see for yourself how your app will behave when calling APIs that it uses fails. With Microsoft Graph Developer Proxy, you can test any kind of app, using any API. Break your app on your box, handle errors gracefully and deploy your app to production with confidence. Your customers will thank you.

Get started at https://aka.ms/graph/proxy.

Synchronising tasks at scale between Bloom Growth and Microsoft To Do

At Rapid Circle, we utilise a framework known as the Enterprise Operating System (EOS), and to help achieve this we use a tool called Bloom Growth (formerly known as Traction Tools).

I won’t get into the specifics of how it works, but one of the things that comes out of our weekly “L10” team meetings is tasks get allocated to people. (This isn’t rocket science, and is possible with many other systems, but Bloom Growth is what we and many organisations use.)

The Challenge

The only issue with tasks being created in Bloom Growth is that they stay in Bloom Growth. If you want to update them or mark them as complete — you need to log into Bloom Growth to do that. Additionally, the only way you’re reminded of the tasks is a daily email — which for many people gets lost in their sea of other reminder emails.

Effective users of the Microsoft 365 platform will use To Do for managing their tasks as it does a great job of individual task lists, shared task lists, and synchronising tasks with Planner.

So how do we connect the two together?

The Solution — v1

As soon as I started using Bloom Growth and was assigned a task, I immediately looked for any form of integration to be able to bring the tasks to where I work — in Microsoft 365. Unfortunately nothing existed that I could find.

A quick search online yielded a positive result — a Bloom Growth v1 API swagger.

The initial solution I built was for myself only using two workflows.

Flow #1

  1. Triggered based on a daily schedule
  2. Connects to Bloom Growth with my account
  3. Checks for any open tasks under my account
  4. Checks to make sure the tasks don’t already exist in To Do
  5. Creates tasks in a specific To Do task list with the Bloom Growth ID appended to the task title (required for Flow #2)

Flow #2

  1. Triggered when a task in the specific To Do list was updated, using a trigger condition to only run for completed tasks
  2. Connects to Bloom Growth with my account
  3. Looks for a task in Bloom Growth that matches the ID in the task title
  4. Marks the task as complete in Bloom Growth

While a few of my colleagues made copies of these workflows for themselves, I heard some of the managers lamenting that their staff were not completing tasks on time for the reasons mentioned above. And while I could go with the approach of walking people through setting it up, ultimately it’s a lot of separate solutions, running under each employee — which can be challenging to support.

Enter…

The Solution v2

While discussing this with one of my colleagues who was using a copy of my two flows, we wondered if there was a way we could do this at scale.

At the time, the Graph documentation for Microsoft To Do did not reflect that application permissions were supported for the endpoints, but I thought I’d try it anyway… and it worked.

So, without further ado, here is how to synchronise tasks from Bloom Growth with Microsoft To Do for large amounts of staff.

This solution utilises 3 workflows:

  • Create a “L10 Tasks” folder for users
  • Check for tasks assigned to them, add them to To Do
  • Check for completed tasks in To Do, mark them as complete in Bloom Growth

Solution Requirements

There are 3 requirements we need for this to work:

Requirement #1: Bloom Growth access

For this solution to work, we need an account with administrator-level access in Bloom Growth, so that it can see the tasks of every single member.

Requirement #2: Azure AD App Registration

In order to be able to read/write everyone’s task lists, we need an Azure AD App Registration with the following permissions:

Create a client secret, and that’s it!

Requirement #3: Table to store user-specific information

For my solution, I used a SharePoint list out of convenience. However, you could use a Dataverse table or something else if you like.

All we need to store in this list is:

  • User Principal Name (UPN)
  • Bloom Growth ID
  • Task list ID

Workflows

Workflow #1: Create the “L10 Tasks” list in To Do

This workflow runs on a regular basis and performs the following functions:

  1. Get members of a security group (so we only apply this to valid users)
  2. Find their Bloom Growth user ID
  3. Create the task list in To Do
  4. Record the details in a table

Of course we need some basic error checking to handle if they already have an existing task list, and secondly whether they actually exist in Bloom Growth.

Sure the workflow is not necessarily as elegant as it could be, but it only takes about 2–3 minutes to run for about 80 users, so I don’t feel the need to optimise it at this point.

Workflow #2: Check for new tasks in Bloom Growth and create them in To Do

This workflow is timed to run after the first workflow, and performs the following functions:

  1. Get the users to run the sync against
  2. For each user, find tasks assigned to them in Bloom Growth
  3. Check if those tasks already exist in the “L10 Tasks” list (using the Bloom Growth task ID as a reference)
  4. If not found, create the task in To Do with the Bloom Growth task ID in the title (used by the previous step, and the next workflow)

Again, this workflow could be more elegant, but it also only takes a whopping 2–3 minutes to run for the 80 users.

Workflow 3: Check for completed tasks in To Do and update their status in Bloom Growth

The first part is the same as Workflow 2, but what it does within the Apply to each is different.

Within the scope we retrieve the Bloom Growth ID of the task from title of the To Do task:

Then we check if the task is still open in Bloom Growth or not (as someone may have already marked it as complete directly in the web portal, and we don’t want to get an error):

The Final Result

Here’s what my tasks look like in Bloom Growth:

And in To Do:

So let’s mark one of these tasks as complete in To Do:

And presto:

You can download the full solution from my PowerThings repository on GitHub.

Appendix — Graph endpoints used

This blog post is already long, so I’ve put the breakouts of the To Do specific API calls down here.

Originally published at Loryan Strant, Microsoft 365 MVP.


Synchronising tasks at scale between Bloom Growth and Microsoft To Do was originally published in REgarding 365 on Medium, where people are continuing the conversation by highlighting and responding to this story.

How to Deal with Common Errors when Running Graph Commands with PowerShell

It's great to be able to run Graph API requests in PowerShell scripts if everything goes right. This article describes why some common Graph API errors occur in scripts and what to do when the errors happen. Most errors are due to permissions assigned to the Azure AD apps used to run scripts and getting the basics will resolve those problems.

The post How to Deal with Common Errors when Running Graph Commands with PowerShell appeared first on Practical 365.

Flaws in the Plan for Microsoft Graph PowerShell SDK V2

Work Ongoing on Other Projects – and Now the Microsoft Graph PowerShell SDK V2 Appears

Due to the deprecation of the Azure AD and Microsoft Online Services (MSOL) PowerShell modules (still scheduled for June 30, 2023), there’s been a lot of activity around upgrading scripts to use cmdlets from the Microsoft Graph PowerShell SDK. This is especially true for any script that performs license management activities as these cmdlets will stop working on March 31, 2023.

Microsoft’s documentation says, “Scripts written in Azure AD PowerShell won’t automatically work with Microsoft Graph PowerShell.” This is incorrect. The scripts won’t work at all because the cmdlets differ. Because the modules are based on very different technologies, no one-to-one translation from Azure AD cmdlets to SDK cmdlets either. Moving to a new module isn’t therefore not a matter of a quick edit to swap cmdlets over. Parameters and outputs differ. The effort needed to upgrade and test even a relatively simple script might extend to half a day or more.

The experience of using the SDK is growing within the technical community, but a knowledge gap still exists at times, especially when searching for good examples of how to accomplish a task. Microsoft’s documentation for the SDK cmdlets has improved recently, but it’s still not at the level that it should be.

Microsoft PowerShell Graph SDK V2

The current situation with the transition from Azure AD to SDK makes me think that Microsoft’s plan for changes in version two of the Microsoft PowerShell Graph SDK are badly flawed. The new version is still in the preview stage so things will probably change before general availability. At least, I hope that they do.

There’s some good changes lined up that I’ll cover first.

Although it’s possible to use V1 of the SDK with an Azure Automation managed identity, the method requires getting an access token from Azure and isn’t as clean as other implementations, such as those for Microsoft Teams and V3.0 of the Exchange Online management module. V2 of the SDK will allow you to connect using:

Connect-MgGraph -Identity

Support for managed identities will extend to user-created managed identities. Another change for authentication is support a credentials prompt when signing into the Graph. Finally, V2 supports certificate-based authentication.

Other changes include support for HTTP/2 and better handling by cmdlets for HTTP status codes.

Breaking Up is Hard to Do

V1 of the SDK is a giant module with 40 sub-modules (like Microsoft.Graph.Authentication). The size and unwieldly nature of the SDK means that it’s more difficult to manage than it should be. For instance, when Microsoft updates the SDK, the sub-modules used by developers on local PCs and in Azure Automation accounts require updating.

One reason why the SDK is so large is that it includes both V1.0 and beta version of cmdlets. This is because the Graph APIs that Microsoft generates the cmdlets from come in V1.0 and beta versions. Microsoft’s solution for the V2 SDK is to deliver separate modules: one for V1.0 (production) and another for beta.

Practical Side-Effects of Breaking the Microsoft Graph PowerShell SDK V2 into Two Modules

Conceptually, I don’t have any issue with the idea of splitting up the SDK into two modules. It’s on a practical level where my concerns kick in.

Today, a script can switch between V1.0 and beta by running the Select-MgProfile cmdlet. I do this all the time because the beta version of many cmdlets deliver more information than their V1.0 counterparts do. For example, Get-MgUser is a basic cmdlet to fetch details of an Azure AD user. The V1.0 cmdlet does not return license assignment data while the beta cmdlet does.

Select-MgProfile v1.0
Get-MgUser -UserId Tony.Redmond@office365itpros.com | fl assign*

AssignedLicenses :
AssignedPlans    :

Select-MgProfile beta
Get-MgUser -UserId Tony.Redmond@office365itpros.com | fl assign*

AssignedLicenses : {f61d4aba-134f-44e9-a2a0-f81a5adb26e4, 61902246-d7cb-453e-85cd-53ee28eec138, 26d45bd9-adf1-46cd-a9e1-51e9a5524128, 4016f256-b063-4864-816e-d818aad600c9...}
AssignedPlans    : {b44c6eaf-5c9f-478c-8f16-8cea26353bfb, fd2e7f90-1010-487e-a11b-d2b1ae9651fc,f00bd55e-1633-416e-97c0-03684e42bc42, 3069d530-e41b-421c-ad59-fb1001a23e11...}

Basic functionality issues afflict V1.0 cmdlets that operate against user accounts, groups, and other Azure AD objects. It would be nice if Microsoft fixed these problems and delivered a solid V1.0 module that allowed developers to focus on V1.0. Instead, the need exists to use the beta cmdlets.

Instead of making sure that many important cmdlets work like they should, Microsoft plans to drop the Select-MgProfile cmdlet. They say that “the profile design made the module bulky and error prone as it combined Microsoft Graph v1.0 and beta commands into a single module.” I accept that combining the two cmdlet sets in a single module is bulky, but is that a reason to remove a useful piece of functionality that allows developers to switch between V1.0 and beta cmdlets as needed? I don’t think it would take a lot of software engineering to figure out how to make the Select-MgProfile cmdlet load and unload modules as needed.

Even worse, Microsoft plans to introduce different names for the cmdlets in the two modules. Cmdlets in the V1.0 module will have the original names like Get-MgUser and Get-MgGroup. The beta cmdlets will have names like Get-MgBetaUser and Get-MgBetaGroup. Microsoft says that an advantage of their approach is that customers will be able to run V1.0 and beta cmdlets in the same script. In my experience, this never happens. Developers use Select-MgProfile to decide what cmdlets to use and then use cmdlets from that set. Mixing and matching cmdlets from different modules overcomplicates things.

Will this command be Get-MgBetaUser in the Microsoft Graph PowerShell SDK V2
Figure 1: Will this command be Get-MgBetaUser in the Microsoft Graph PowerShell SDK V2

The suggestion of using different names for cmdlets is just silly. It means that a developer must decide what module they want to use for a script up front to know what cmdlet names to use. Developers must check every existing script to identify if the correct cmdlet names are in place (and to deal with the Select-MgProfile issue). All the work done to upgrade scripts from the Azure AD and MSOL modules will need revalidation. That’s work Microsoft is forcing on tenants at a time when the Exchange development group wants tenants to upgrade their Exchange scripts to remove dependencies on Remote PowerShell. Forcing tenants to upgrade scripts for Exchange and Azure AD at the same time is an example of a lack of joined-up thinking within Microsoft.

I hear that Microsoft might generate a tool to help developers move to V2 by updating references to the beta cmdlets to use the new names. That might help, but work still needs to be done to review scripts before and after the tool runs and test to make sure that the updated script works. And what happens if Microsoft updates the V1.0 cmdlets and a decision is made to revert to that version? You’ll still have to update scripts manually.

A Way Forward for the Microsoft Graph PowerShell SDK V2

What I would like to see done in the Microsoft Graph PowerShell SDK V2 is:

  • Repurpose the Select-MgProfile cmdlet so that it switches between the two modules as transparently as possible.
  • Keep the same cmdlet names in both modules. It then becomes a choice for the developer as to which cmdlets to use.
  • Fix the V1.0 of basic user and group cmdlets like Get-MgUser and Get-MgGroup so that they return the information necessary to get real work done. If the V1.0 cmdlets delivered that functionality, the need to switch to beta wouldn’t be as pressing. The problems must be fixed in the Graph API rather than the SDK (which simply replicates what the Graph API does).

The precedent for having cmdlets with the same name in production and development modules exists. We’ve used the AzureAD and AzureADPreview modules in this manner for years. Why Microsoft can’t do the same with V2 of the Microsoft Graph PowerShell SDK is beyond me.

In any case, the first preview version of the Microsoft Graph PowerShell SDK V2 is available to download from the PowerShell Gallery. Test it and see what you think. The important thing is to give feedback to Microsoft (you can comment in GitHub). If you don’t, then the current plan is what will flow through to the Generally Available release of the Microsoft Graph PowerShell SDK V2 sometime in 2023.


So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.

Microsoft Clarifies How It Plans to Charge for APIs

Pay as You Go Model for Microsoft 365 APIs

Microsoft 365 APIs

About fifteen months ago, Microsoft introduced the notion of metered APIs where those who consumed the APIs would pay for the resources they consume. The pay-as-you-go (PAYG) model evolved further in July 2022 when Microsoft started to push ISVs to use the new Teams export API instead of Exchange Web Services (EWS) for their backup products. The Teams export API is a metered API and is likely to the test case to measure customer acceptance of the PAYG model.

So far, I haven’t heard many positive reactions to the development. Some wonder how Microsoft can force ISVs to use an API when they don’t know how high the charges metering will rack up. Others ask how Microsoft can introduce an export API for backup when they don’t have an equivalent import API to allow tenants to restore data to Teams. I don’t understand this either as it seems logical to introduce export and import capabilities at the same time. We live in interesting times!

PAYG with Syntex Backup

To be fair to Microsoft, they plan to go down the same PAYG route with the new backup service they plan to introduce in 2023 as part of the Syntex content management suite. Customers will have to use an Azure subscription to pay for backups of SharePoint Online, OneDrive for Business, and Exchange Online (so far, Microsoft is leaving Teams backup to ISVs).

All of which brings me to the December 2 post from the Microsoft Graph development team where Microsoft attempts to describe what they’re doing with different Microsoft 365 APIs. Like many Microsoft texts, too many words disguise the essential facts of the matter.

Three Microsoft 365 API Tiers

Essentially, Microsoft plans to operate three Microsoft 365 API tiers:

  • Standard: The regular Graph-based and other APIs that allow Microsoft 365 tenants to access and work with their data.
  • High-capacity: Metered APIs that deal with high-volume operations like the streaming of data out of Microsoft 365 for backups or the import of data into Microsoft 365.
  • Advanced: APIs developed by Microsoft to deliver new functionality. Microsoft points to Azure Communications Services as an example. These APIs allow developers to add the kind of communication options that are available in Teams to their applications.

My reading of the situation is that Microsoft won’t charge for standard APIs because this would interfere with customer access to their data. Microsoft says that standard APIs will remain the default endpoint.

However, Microsoft very much wants to charge for high-capacity APIs used by “business-critical applications with high usage patterns.” The logic here is that these APIs strain the resources available within the service. To ensure that Microsoft can meet customer expectations, they need to deploy more resources to meet the demand and someone’s got to pay for those resources. By using a PAYG model, Microsoft will charge for actual usage of resources.

Microsoft also wants customers to pay for advanced APIs. In effect, this is like an add-on license such as Teams Premium. If you want to use the bells and whistles enabled by an advanced API, you must pay for the privilege. It’s a reasonable stance.

Problem Areas for Microsoft 365 APIs

I don’t have a problem with applying a tiered model for APIs, especially if the default tier continues with free access. The first problem here is in communications, where Microsoft has failed to sell their approach to ISVs and tenants. The lack of clarity and obfuscation is staggering for an organization that employs masses of marketing and PR staff.

The second issue is the lack of data about how much PAYG is likely to cost. Few want to write an open-ended check to Microsoft for API usage. Microsoft is developing the model and understands how the APIs work, so it should be able to give indicative pricing for different scenarios. For instance, if I have 100 teams generating 35,000 new channel conversations and 70,000 chats monthly, how much will a backup cost? Or if my tenant generates new and updated documents at the typical rate observed by Microsoft across all tenants of a certain size, how much will a Syntex backup cost?

The last issue is the heavy-handed approach Microsoft has taken with backup ISVs. Being told that you must move from a working, well-sorted, and totally understood API to a new, untested, and metered API is not a recipe for good ISV relationships. Microsoft needs its ISVs to support its API tiered model. It would be so much better if a little less arrogance and a little more humility was obvious in communication. Just because you’re the big dog who owns the API bone doesn’t mean that you need to fight with anyone who wants a lick.


Make sure that you’re not surprised about changes that appear inside Office 365 applications by subscribing to the Office 365 for IT Pros eBook. Our monthly updates make sure that our subscribers stay informed.

Creating a SharePoint page using Microsoft Graph API and Power Automate

Thanks to the workflow that notifies me of updates to the Microsoft Graph API, I saw a new addition to the list: the sitePage resource type.

This is exciting for me, as I currently have some workflows that distribute SharePoint pages to various sites both within our own tenant, as well as client tenants. Currently these are triggered by a page being published in a central location, with specific information used as trigger conditions.

What’s annoying about this scenario is that I need to create connectors in Power Automate to the client tenant using an account in their environment. It also means I need a workflow per client (to keep it clean).

Now with the addition of the sitePage resource type in Microsoft Graph, I can make this work programmatically across any number of clients — all from a single workflow.

WARNING: This is a beta feature at present, so don’t use it for production systems unless you’re find to accept the risks.

Requirements

The requirements of this are fairly simple. We need:

  • An app registration in Azure AD that has the “Sites.ReadWrite.All” application permission added
  • A repository where the details are stored, including:
  • Client name
  • Tenant ID
  • App/Client ID
  • Secret
  • SharePoint site ID

Now, we could use a different way to authenticate, and we could also use an action to perform a search in the tenant to find the relevant site by name or URL, but if we’ve got that — then it’s not exactly difficult to get the SharePoint site ID and store it in our repository.

For the purposes of this, I’m going to store it in a SharePoint list:

Workflow

At a high-level, my workflow is quite simple:

In my specific scenario, all the workflow is doing is publishing a page with an embedded video, as part of a program of regular content I create for clients. So all I need to provide is a page title and the URL suffix from the embed code.

The next step of the workflow takes my page title, and turns it into a file name:

The code used here is:

concat(replace(triggerBody()['text'],' ','-'),'.aspx')

From here, we’re now ready to retrieve all the sites we want to apply this to:

Within our Apply to Each, we have three steps:

  1. Create the page
  2. Parse the JSON of the page creation
  3. Publish the page, using the ID from step 2

(If you’re comfortable with extracting the page ID value directly from the results of step 1, then you don’t need the Parse JSON action.)

In the page creation action, I’m creating a very simple page that only has a single embed web part on it, and I’m passing variables from both the trigger as well as the Get Items action.

The Parse JSON is relatively straightforward:

And for the final step we hit publish on the page:

And that’s it! We have a simple page published in each tenant listed, with the same content.

If you want something more glamorous, refer to the sitePage resource type page to get a breakdown of the structure of the body of the content.

Appendix

Here’s the full details of the body of the page creation and Parse JSON actions.

Create page

{
"name": "@{outputs('Compose_-_replace_spaces_with_hyphens_and_add_file_extension')}",
"title": "@{triggerBody()['text']}",
"pageLayout": "article",
"promotionKind": "newsPost",
"showComments": false,
"showRecommendedPages": false,
"titleArea": {
"enableGradientEffect": true,
"imageWebUrl": "/_layouts/15/images/sleektemplateimagetile.jpg",
"layout": "plain",
"showAuthor": false,
"showPublishedDate": true,
"showTextBlockAboveTitle": false,
"textAboveTitle": "",
"textAlignment": "left",
"imageSourceType": 2,
"title": "@{triggerBody()['text']}"
},
"canvasLayout": {
"horizontalSections": [
{
"layout": "oneColumn",
"id": "1",
"emphasis": "none",
"columns": [
{
"id": "1",
"webparts": [
{
"id": "669d4d75-eca0-4e8b-95d7-2e765dd4859a",
"webPartType": "490d7c76-1824-45b2-9de3-676421c997fa",
"data": {
"audiences": [],
"dataVersion": "1.2",
"description": "Embed content from other sites such as Sway, YouTube, Vimeo, and more",
"title": "Embed",
"properties": {
"embedCode": "<iframe src=\"https://player.vimeo.com/video/@{triggerBody()['text_2']}\" width=\"640\" height=\"360\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"\"></iframe>",
"cachedEmbedCode": "<iframe src=\"https://player.vimeo.com/video/@{triggerBody()['text_2']}\" width=\"640\" height=\"360\" frameborder=\"0\" allow=\"autoplay; fullscreen; picture-in-picture\" allowfullscreen=\"\"></iframe>",
"shouldScaleWidth": true,
"thumbnailUrl": "",
"cachedEmbedCodeThumbnail": ""
},
"serverProcessedContent": {
"imageSources": [
{
"key": "imageSource",
"value": "/_LAYOUTS/IMAGES/VISUALTEMPLATEIMAGE1.JPG"
}
]
}
}
}
]
}
]
}
]
}
}

Parse JSON

{
"type": "object",
"properties": {
"@@odata.context": {
"type": "string"
},
"@@odata.etag": {
"type": "string"
},
"eTag": {
"type": "string"
},
"id": {
"type": "string"
},
"lastModifiedDateTime": {
"type": "string"
},
"name": {
"type": "string"
},
"webUrl": {
"type": "string"
},
"title": {
"type": "string"
},
"pageLayout": {
"type": "string"
},
"thumbnailWebUrl": {
"type": "string"
},
"promotionKind": {
"type": "string"
},
"showComments": {
"type": "boolean"
},
"showRecommendedPages": {
"type": "boolean"
},
"createdBy": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
}
}
}
}
},
"lastModifiedBy": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"displayName": {
"type": "string"
}
}
}
}
},
"parentReference": {
"type": "object",
"properties": {
"siteId": {
"type": "string"
}
}
},
"contentType": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
}
},
"publishingState": {
"type": "object",
"properties": {
"level": {
"type": "string"
},
"versionId": {
"type": "string"
}
}
},
"reactions": {
"type": "object",
"properties": {}
},
"titleArea": {
"type": "object",
"properties": {
"enableGradientEffect": {
"type": "boolean"
},
"imageWebUrl": {
"type": "string"
},
"layout": {
"type": "string"
},
"showAuthor": {
"type": "boolean"
},
"showPublishedDate": {
"type": "boolean"
},
"showTextBlockAboveTitle": {
"type": "boolean"
},
"textAboveTitle": {
"type": "string"
},
"textAlignment": {
"type": "string"
},
"title": {
"type": "string"
},
"authors@odata.type": {
"type": "string"
},
"authors": {
"type": "array"
},
"authorByline@odata.type": {
"type": "string"
},
"authorByline": {
"type": "array"
},
"imageSourceType": {
"type": "integer"
},
"serverProcessedContent": {
"type": "object",
"properties": {
"imageSources": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"key",
"value"
]
}
}
}
}
}
}
}
}

Originally published at Loryan Strant, Microsoft 365 MVP.


Creating a SharePoint page using Microsoft Graph API and Power Automate was originally published in REgarding 365 on Medium, where people are continuing the conversation by highlighting and responding to this story.

Renommer facilement un canal Teams avec Graph, Power Automate et le connecteur HTTP with Azure AD

Il arrive parfois que le bloc action que vous recherchez dans Power Automate n’existe pas. Par exemple avec le connecteur Teams, il est possible de créer un canal dans une équipe Teams mais il n’existe aucune action pour renommer un canal. Cependant cela est réalisable avec le service graph.

Il est maintenant plus simple d’effectuer des actions avec Graph depuis Power Automate grâce au connecteur ‘HTTP with Azure AD’ qui est un connecteur premium.

Voici la marche à suivre pour utiliser simplement Graph dans Power Automate.

Utilisez le connecteur ‘HTTP with Azure AD’ dans Power Automate

Ce connecteur va vous permettre d’interroger l’API Graph sans avoir à passer par une application ou à récupérer un jeton de connexion au préalable.

Pour cela ajoutez l’action « Invoquer une requête HTTP » dans un Power Automate.

Puis configurez votre action, dans mon cas je souhaite utiliser Graph. J’indique donc l’url du service que je souhaite interroger : https://graph.microsoft.com.

Il suffit maintenant de réaliser sa requête, pour cela n’hésitez pas à vous rendre sur le site Graph Explorer afin de prendre connaissance des requêtes possibles.

Ci-dessous, un exemple pour récupérer les informations de son profil.

Ci-dessous le résultat :

Utilisez la requête suivante pour renommer un canal Teams

Il vous suffit de changer la requête pour renommer votre canal Teams.
Attention : Vous devez avoir le droit de renommer le canal de l’équipe Teams.

Type : Il faudra faire une requête de type Patch.
Url : L’Url de la requête sera la suivante : https://graph.microsoft.com/v1.0/teams/(‘Guid de votre équipe Teams’)/channels/(‘Id de votre canal’)
Voici un exemple de d’url : https://graph.microsoft.com/v1.0/teams/35e93c78-xxxx-4b72-8432-5db8b61xxxxx/channels/19:xxxxx98012c24afaxxxx982338954b05@thread.tacv2 .
Contenu : Il doit indiquer le nouveau nom de votre canal dans le paramètre displayName.
{
« displayName »: « Nouveau com du canal »
}

Vous savez maintenant renommer un canal Teams et utiliser Graph à l’aide d’un seul bloc action dans Power Automate. A vous de jouer 😀

La documentation concernant l’API Graph est disponible ici.

actionhttpazuread-1

franckcatinot

Récupérer des données depuis Graph dans PowerApps à l’aide de Flow

L’objectif de cet article est de découvrir comment intégrer Graph dans PowerApps.

Dans un premier temps, nous allons créer une application de type canevas dans PowerApps.

PowerAppsCreer

Ajouter deux étiquettes ainsi qu’un bouton qui permettra de charger vos données.

Il faut maintenant créer un connecteur personnalisé lot Microsoft Graph JSON pour Microsoft Flow. Pour cela veuillez suivre le lien suivant https://docs.microsoft.com/fr-fr/graph/tutorials/flow

Dans mon cas, j’ai donné uniquement l’autorisation User.ReadWrite de type délégué à l’application.

Une fois votre connecteur en place dans Flow, alors vous pouvez lier votre bouton PowerApps vers Flow.

PowerAppsAjouterFlow

Par défaut le trigger de votre Flow sera PowerApps, nous ajouterons ensuite l’action personnalisée de votre connecteur définit précédemment dans Flow, dans mon cas je l’ai appelé Graph.
Ensuite je complète le champ body de mon Action « Graph » afin d’effectuer la requête « https://graph.microsoft.com/v1.0/me/ ».

BodyRequest

Puis je lance mon Flow pour tester son fonctionnement.

CorpsConnecteurFlow

Dans l’historique des exécutions de mon Flow, je remarque que celui-ci a fonctionné. Je copie le corps de la sortie de ma requête.

J’édite de nouveau mon Flow, j’ajoute une action « Réponse », et j’ajoute le texte copié précédemment dans la pop-up « Utiliser l’exemple de charge utile pour générer le schéma » afin que le composant génère le bon Schéma JSON.

Information : Je n’ai pas ajouté l’action « répondre à PoweApps » afin de retourner le résultat de la requête, car celle-ci est seulement capable de nous retourner des résultats de type texte, booléen, fichier, messagerie, nombre et date et non pas des tables ou objets.

GenerationJsonFlow

Je clique sur terminer et je modifie le JSON afin que la réponse soit correcte.

Information : Si votre JSON ne correspond pas à la réponse de votre requête ou qu’il contient une erreur alors l’application PowerApps va probablement générer une erreur.

J’ajoute dans corps de l’action « Réponse » de ma requête précédente et je sauvegarde mon Flow.

ReponseFlow

Je peux maintenant retourner sur PowerApps, mon Flow est disponible.

Je stocke le résultat du Flow dans la variable globale me, lors du clique sur mon bouton ajouté précédemment.

ChargerDonnees

Je peux maintenant observer les valeurs retournées, dans les étiquettes définies précédemment. Mon premier champ texte affichera le display name de l’utilisateur courant tandis que le second affichera son adresse mail.

AfficherDonnees

Je lance mon application, et lorsque je clique sur le bouton « Charger les données » le display name et l’adresse mail de l’utilisateur courant apparaissent.

Resultat

Et voilà 😊 Vous êtes maintenant capable d’utiliser Graph depuis PowerApps. N’oubliez pas de modifier les droits de votre application, si jamais vos appels depuis Flow nécessitent plus d’autorisations.

laptop-3190194_960_720

franckcatinot

PowerAppsCreer

PowerAppsAjouterFlow

BodyRequest

CorpsConnecteurFlow

GenerationJsonFlow

ReponseFlow

ChargerDonnees

AfficherDonnees

Resultat

Ignite 2022: Curated list of posts from Microsoft related to Microsoft 365 and Power Platform

Microsoft Ignite 2022 brought several amazing announcements across all the Microsoft cloud platform.

If you interested in updates related to Microsoft 365 collaboration tools (SharePoint/Teams/Viva & related) and the Power Platform and want to know more details, or in case you missed any updates, here is a curated list of posts from Microsoft official blogs & sites released during Ignite with most of the relevant news:

SharePoint

Microsoft Lists announcements at Ignite 2022

Introducing Microsoft Syntex: Context AI in the flow of work

What’s new in Security and Management in SharePoint, OneDrive, and Teams – Microsoft Ignite 2022

Stream (on SharePoint) is now generally available

Microsoft Viva

Announcing new Microsoft Viva IT Admin features

Connect daily work to OKRs with our latest Viva Goals integrations

Microsoft Ignite 2022: Innovations and roadmap for Microsoft Viva

Microsoft Viva Insights – new productivity and wellbeing experiences coming soon

Storyline in Viva Engage and Microsoft 365 is now generally available

Viva Learning announcements at Ignite 2022

Viva Topics: New adoption dashboard and experiences in Teams Channels, Viva Connections and Outlook

What’s new in Viva Connections

Microsoft Teams

Enhance collaboration with Microsoft Teams chat and channels features for the hybrid workplace

Introducing Mesh avatars for Microsoft Teams in Private Preview

Introducing Microsoft Teams Premium, the better way to meet

What’s New in Microsoft Teams | Microsoft Ignite 2022

Microsoft 365 Developmemt

Boost your Microsoft Teams app experience with new link unfurling capabilities

Ignite 2022: Transforming collaboration with low and pro code dev tools

Scale access to Microsoft 365 data with Microsoft Graph Data Connect

Updates to Microsoft Teams API in Microsoft Graph 

Updates to the Planner API in Microsoft Graph

What’s new for Office Add-ins at Ignite 2022

Microsoft 365 – Other Apps

Introducing Microsoft Places: Turn your spaces into places

From bolt-on to built-in information protection in Microsoft 365 Apps

Customize retention and deletion to help meet your specific business requirements

Introducing new AI enhancements in Microsoft 365: New features coming to Microsoft Editor and more!

Microsoft Editor using Context IQ in Outlook on the web and Word for the web coming soon!

Microsoft Loop at Ignite 2022

Power Platform

Leverage low-code to do more with less at Microsoft Ignite 2022 

The future of low-code governance with Managed Environments for Power Platform

Microsoft Power Pages is now generally available

New ways to innovate with AI and Microsoft Power Automate

Power BI: Introducing Cross-tenant Power BI Dataset Sharing

Power BI: Microsoft Ignite 2022: Do more with enterprise self-service business intelligence

Power Automate: Automate Document Processing end-to-end with AI Builder

Power Automate: Begin your Robotic Process Automation modernization journey

Satya Nadella Ignite 2022 Keynote

Satya Nadella Ignite 2022 Keynote – YouTube

Ignite 2022 Book of News

Ignite 2022 Book of News (Updates across all Microsoft Cloud)

Final thoughts

Did you find any additional interesting post? Feel free to leave the link in the comments!

Follow me on Twitter and LinkedIn for Microsoft 365 and Power Platform updates and tips!

The post Ignite 2022: Curated list of posts from Microsoft related to Microsoft 365 and Power Platform appeared first on michelcarlo.

Calling Graph API using a flow and manipulating the results from Power Apps using the ParseJSON function

Recently I posted about using a generic flow to call the SharePoint Rest API from a canvas app and parse the results using the ParseJSON experimental function, in a way that we can almost simulate as if we could call the SharePoint Rest API from a canvas app.

The same technique can be applied to call Microsoft Graph API, as in the example below where we retrieve the list of group members from a Microsoft 365 group, including nested group members (an action that cannot be done using the standard Microsoft 365 Groups action):

Why call Graph if we have Office 365 products connectors and actions in Power Apps?

Even though there are several actions available for Office 365 products in Power Apps, they don’t fully cover what we can accomplish using Microsoft Graph. For example, some actions we could do with Graph that are not available out-of-the-box (explained below in this blog post):

  • Create a Microsoft 365 Group
  • List nested groups members from an Office 365 group
  • Dynamically detect the root SharePoint site of the tenant (useful if you want to grab this value and make an app or flow ‘tenant agnostic’ while running HTTP requests to SharePoint)

There is an existing and direct ‘Send an HTTP Request’ option from the Office 365 Groups connector in Power Apps canvas apps, but this option runs the queries but doesn’t return objects as results (it only returns a boolean). Hence, this technique of calling a Power Automate flow and returning the results is useful.

Before creating the flow and calling it from the Canvas App, enable the experimental feature as explained in my previous post.

Creating the Flow

To keep using only standard licenses, let’s use the action ‘Send an HTTP Request’ from the Office 365 connectors.

To simplify the use case, in this Flow let’s only require the Graph endpoint, method and request body in the Trigger (Power Apps V2):

Add a ‘Send an HTTP Request’ action from the Office 365 Groups connector after the trigger, as below. In this example, we already prepend the path ‘https://graph.microsoft.com’ to the field, so we can only specify the endpoint piece of Graph when calling it from Power Apps:

The final action is simply to pass the response back to Power Apps:

Sending requests and parsing the results from Power Apps

Save the flow with the name ‘GraphHTTP’ and add it to your canvas app from the Power Automate pane:

Now that the Flow is added, you can then call Graph from the flow and parse the results back as in the examples below.

Listing Group Members

The sample query below runs a GET request against the groups segment in Microsoft Graph and lists all group members (including nested members) using the Flow, stores it in a String variable named locResponseBody, parses it using the ParseJSON function and then converts it to a proper table of typed objects by using a combination of AddColumns + DropColumns formulas (adding custom columns with transformed values, then removing the original ‘Value‘ property), which is stored in a collection named colGroupMembers (replace yourGroupIdGuid by your Group Id).

UpdateContext(
    {
        locResponseBody: GraphHTTP.Run(
            "/v1.0/groups/efbc5736-1cf4-4df6-81b0-05136d3d992f/transitiveMembers/microsoft.graph.user",//Graph endpoint
            "GET",//HTTP Method           
            ""//Body, in case it's needed
        ).body
    }
);
ClearCollect(
    colGroupMembers,
    DropColumns(
        AddColumns(
            Table(ParseJSON(locResponseBody).value),
            "id",Text(Value.id),
            "displayName",Text(Value.displayName),
            "givenName",Text(Value.givenName),
            "surname", Text(Value.surname),
            "jobTitle",Text(Value.jobTitle),
            "mail",Text(Value.mail),
            "userPrincipalName",Text(Value.userPrincipalName),
            "businessPhones",ForAll(Table(Value.BusinessPhones),Text(Value)),
            "officeLocation",Text(Value.officeLocation),                        
            "preferredLanguage",Text(Value.preferredLanguage),
            "mobilePhone",Text(Value.mobilePhone)
        ),
        "Value"
    )
)

Creating a Microsoft 365 Group

In the example below, the Flow is used to call Graph and create a Microsoft 365 group from a Canvas App (and store the response as an object in the local variable locGroupObject) by calling a POST request against the groups segment in Graph and passing the details of the group to be created in the request body:

UpdateContext(
    {
        locResponseBodyGroupAdded: GraphHTTP.Run(
            "/v1.0/groups",//Graph endpoint
            "POST",//HTTP Method                      
            "{
                'description': 'test group 123',
                'displayName': 'test group description 123',
                'groupTypes': [
                   'Unified'
                 ],
                'mailEnabled': true,
                'mailNickname': 'testGroup123',
                'securityEnabled': false,
                'visibility': 'Private'
            }"//Body                       
        ).body
    }
);
UpdateContext(
    {
        locGroupObject: With(
            {jsonItem: ParseJSON(locResponseBodyGroupAdded)},
            {
                Id: Text(jsonItem.id),
                Description: Text(jsonItem.description),
                DisplayName: Text(jsonItem.displayName),
                GroupTypes: ForAll(
                    Table(jsonItem.groupTypes),
                    Text(Value)
                ),
                Mail: Text(jsonItem.mail),
                MailEnabled: Boolean(jsonItem.mailEnabled),
                MailNickname: Text(jsonItem.mailNickname),
                Visibility: Text(jsonItem.visibility)
            }
        )
    }
);

Getting the address of the SharePoint root site of the tenant

In the example below, the Flow is used to call Graph and retrieve the root SharePoint site address of the tenant by running a simple GET request against the sites/root segment in Graph:

UpdateContext(
    {
        gblTenantRoot: Text(
            ParseJSON(
                GraphHTTP.Run(
                    "/v1.0/sites/root",
                    "GET",
                    ""
                ).body
            ).webUrl
        )
    }
)

Conclusion

The standard action ‘Send an HTTP Request’ in the Office 365 Groups connectors does not give us objects as responses, but we can use a Power Automate flow to do the job in this case.

This enables extra scenarios for querying and actions in Graph beyond the standard ones, within the endpoints that are accepted by the ‘Send an HTTP Request’ action under Office 365 Groups.

Remember that the ParseJSON feature is experimental, so for now it should not be used in Production apps.

References

ParseJSON function in Power Apps (experimental) – Power Platform | Microsoft Docs

List members – Microsoft Graph

List transitive members – Microsoft Graph

Create group – Microsoft Graph

The post Calling Graph API using a flow and manipulating the results from Power Apps using the ParseJSON function appeared first on michelcarlo.

An Unfortunate `API access` UI in the SharePoint Admin Center

Orchestry is a partner of ours at Sympraxis. (Ask us about them anytime!) We love their toolset and recommend them frequently to our clients to improve their governance and provisioning activities. The stuff they build is incredibly powerful – and reliable.

That’s why I was really surprised when I added the Orchestry People List Web Part to a site home page and I didn’t see the actual people, just what looked like placeholders for them. The counts were right, but no details. (This Web Part is better than the out of the box People Web Part because you can set it to show Site Owners and/or Site Members automagically.)

As I am wont to do, I asked my friends at Orchestry what the scoop was. Turns out, it wasn’t an Orchestry problem. The issue was rooted in a really bad user interface in the SharePoint Admin Center.

Here’s what happened. Way back in March, I installed the PnP Modern Search Web Parts. They are just about my favorite tools to use with SharePoint, and I install them as soon as I start working in a tenant. In many cases, I don’t bother the Global Admin to approve the Microsoft Graph permissions for PnP Modern Search, because we can accomplish what we need just using SharePoint Search.

In the screenshot below, you can see the pending request for PnP Modern Search (red box) as well as the Approved requests which Orchestry needed (green box).

The unfortunate part of his UI is because PnP Modern Search “asked” for User.Read.All first, it still “owns” that request.

What we should have seen in the UI was four requests for Orchestry, like so:

Because PnP Modern Search had already asked for User.Read.All, there were only three. The Global Admin approved the three and we called it a day.

Note what happens in that UI after the requests are approved. We lose all the info about which app needed the permissions and when they were granted. No bueno.

Leaving the security implications of all this aside (but keeping in mind this UI exists only for security purposes!), there’s no way for us to see what solution requested the API access, when it was requested, or who approved it after the fact.

Believe it or not, the solution to fix the Orchestry Web Part issues was to approve the User.Read.All permission for PnP Moden Search. That makes sense, right? (No, no it doesn’t at all.)

Final Score:

  • Orchestry 1
  • Microsoft 0

#66 Will your app fail when throttled?

#66 Will your app fail when throttled?

On a tenant of one, your app never fails. Calling Microsoft Graph and other APIs on Microsoft 365 just works. But when it gets used at scale in production, only then you get to see if you built it correctly.

When you build a great application, and it gets widely adopted, it's used a lot. Depending on the size of your organization, your app might be used by hundreds or thousands of simultaneous users, issuing even more requests to Microsoft Graph and other APIs. Microsoft Graph can handle a lot, but even it has its limits, and when you reach them, by calling Graph APIs too often, instead of a response with data, you'll get errors like 429 Too Many Requests. You're throttled.

Throttling is temporary. It's a mechanism to help servers resume regular service operation. By instructing clients to back off for a bit, servers hosting cloud APIs get a chance to get back to normal operation. That's the good news. The bad news is, that, unless you use an SDK that does it for you, you need to handle throttling yourself.

The problem with throttling is that it's elusive. It occurs only in certain conditions. This makes it really hard to test how your app will react when throttled: will it back off and wait as instructed, or will it break with an exception?

This is exactly why we built the Microsoft Graph Developer Proxy: a tool to help you test how your apps respond to API errors. Seeing is believing for a reason. With the Graph Developer Proxy, you no longer need to hope for the best. You can verify, even on your tenant of one, how your app will react when suddenly Graph APIs will return errors.

🙋‍♂️ Download the Graph Developer Proxy, test your apps, and I'm looking forward to hearing what you learned.

PS. You can use Microsoft Graph Developer Proxy with any type of app: client-side apps running in the browser or back-end services running on a server.

#65 Find meeting times and schedule a meeting using Microsoft Graph

#65 Find meeting times and schedule a meeting using Microsoft Graph

In my last newsletter, I shared with you a few resources to help you get started building apps for Microsoft 365. If you work with an organization that uses Microsoft 365 for work, you've got a great opportunity to use your developer skills and bring data and insights stored on Microsoft 365 into your work apps.

Recently I've been working on another app that shows how you'd find meeting times and schedule a meeting for you and other people in your organization. This is a common scenario for work apps, and while it's available in Outlook, having it directly in the work app helps your colleagues stay in the flow of work.

📝 Check out the article I published about this scenario on freeCodeCamp.

📺 Here's also a recording from a recent community call where I showed the app in action.

👾 And if you're interested in digging into it some more, here's the code.

Remember, the best way to check the app out, is to see it running. Follow the setup steps in the readme and run it on your tenant.

I've got some more ideas for new demos that I'll be working on in the coming weeks, so stay tuned for more updates. Meanwhile, if you've got any questions, don't hesitate to reach out by leaving a comment.

Find a meeting time and schedule a meeting on Microsoft 365

Find a meeting time and schedule a meeting on Microsoft 365

Many work apps need the ability to schedule a meeting with others in their organization. Here's how to do it for apps connected to Microsoft 365.

Work apps need work data

Work apps serve a specific purpose: they help you track projects, follow orders or manage resources. But rarely do they contain all the information that users need to complete their work. Typically, information about people, their calendars, or communication is stored elsewhere, like in Microsoft 365. And that's a shame because completing a task requires users to switch between different apps, which is detrimental to their productivity. Unless of course, you bring work data into your work app.

Find a meeting time and schedule a meeting on Microsoft 365

A common scenario for work apps is to schedule a meeting with others in the organization. While it sounds trivial, the app must be able to access attendees' calendars, find a suitable meeting time and schedule the meeting. And that's where Microsoft Graph comes in.

Recently I published an article on freeCodeCamp that shows you how to build an app connected to Microsoft 365 that can find a meeting time and schedule a meeting.

The app shows you how to make the best use of features available in the Microsoft Graph Toolkit and Microsoft Graph to build a UI that you could integrate with another app.

Check it out, and I'm looking forward to hearing what you think!

Show upcoming meetings for a Microsoft 365 user with Microsoft Graph Toolkit

Show upcoming meetings for a Microsoft 365 user with Microsoft Graph Toolkit

Recently, I showed you how you can build in under 10 minutes a simple personal assistant that shows users meetings they have left for the day. Here's an even easier way to do it using the Microsoft Graph Toolkit.

Show upcoming meetings for a Microsoft 365 user

Showing upcoming meetings is a common scenario when integrating Microsoft 365 in work applications. Using Microsoft Graph, your app can connect to Microsoft 365 and access a user's calendar. By building a specific query, you can retrieve meetings between now and the end of the day.

Recently, I walked you step by step how to complete this scenario in under 10 minutes using the Microsoft Graph JavaScript SDK. But there's an even easier way to do it using the Microsoft Graph Toolkit.

The easiest way to connect to Microsoft 365

Microsoft Graph Toolkit (MGT) is a set of components and authentication providers connected to Microsoft 365. MGT takes away the complexity of implementing authentication, loading data from Microsoft Graph, and showing it in your app. And if anything goes wrong, it also properly handles exceptions. Microsoft Graph Toolkit's components are highly customizable so that you adjust them to your app.

A quick comparison: signing in to your app

To understand the benefits of using Microsoft Graph Toolkit, let's have a look at an example: let users sign in to your app using their Microsoft 365 account.

Typically, you'd need code similar to the following:

<html>
<head>
  <title>Upcoming meetings</title>
  <script src="https://alcdn.msauth.net/browser/2.28.3/js/msal-browser.min.js"></script>
</head>
<body>
  <h1>Upcoming meetings</h1>
  <div id="auth"></div>
  <script>
    (() => {
      const scopes = ['Calendars.Read'];
      const msalConfig = {
        auth: {
          clientId: '021aa7bb-9aaa-4185-92ad-c7b75a7fb9d2'
        }
      };
      const msalClient = new msal.PublicClientApplication(msalConfig);

      function render() {
        msalClient
          .handleRedirectPromise()
          .then(response => {
            const accounts = msalClient.getAllAccounts();

            if (accounts.length === 0) {
              document.querySelector('#auth').innerHTML = '<button>Login</button>';
              document.querySelector('#auth button').addEventListener('click', login);
            }
            else {
              document.querySelector('#auth').innerHTML = '<button>Logout</button>';
              document.querySelector('#auth button').addEventListener('click', logout);
            }
          });
      }

      function login(e) {
        e.preventDefault();
        msalClient.loginRedirect({
          scopes
        });
      }

      function logout(e) {
        e.preventDefault();
        msalClient.logoutRedirect();
      }

      render();
    })();
  </script>
</body>
</html>

In comparison, here's the same functionality built using Microsoft Graph Toolkit:

<html>
<head>
  <title>Upcoming meetings</title>
  <script src="https://unpkg.com/@microsoft/mgt@2/dist/bundle/mgt-loader.js"></script>
</head>
<body>
  <h1>Upcoming meetings</h1>
  <mgt-msal2-provider client-id="021aa7bb-9aaa-4185-92ad-c7b75a7fb9d2" scopes="Calendars.Read"></mgt-msal2-provider>
  <mgt-login></mgt-login>
</body>
</html>

See the difference? And we didn't even get to the good part yet: calling Microsoft Graph!

With Microsoft Graph Toolkit you can focus on building your app and solving problems for your customers. Microsoft Graph Toolkit takes care of the rest.

Show upcoming meetings with Microsoft Graph Toolkit

To give you a more complete comparison, I rebuilt the same scenario using Microsoft Graph Toolkit.

The best way to check out the app is to run the app locally by following the instructions in the README.

Browser window with a web page showing upcoming meetings for a user

Because retrieving the data using MGT is so simple, I added some extra UI to differentiate between the different states of the app.

The MGT Agenda component, which I use to show the upcoming meetings offers different templates to customize the UI. When loading the data, I show a simple text message:

<mgt-agenda>
  <template data-type="loading">
    <div class="loading">Loading...</div>
  </template>
  <!-- trimmed for brevity -->
</mgt-agenda>

When there's no data to show, I take into account the fact that there might be no data because the user hasn't signed in to the app yet, or that the user might have no upcoming meetings:

<mgt-agenda>
  <template data-type="loading">
    <div class="loading">Loading...</div>
  </template>
  <template data-type="no-data">
    <div class="no-data" data-if="mgt.Providers.globalProvider.state === mgt.ProviderState.SignedIn">
      <!-- No upcoming meetings -->
    </div>
    <div class="no-data" data-else>
      <p>Sign in to view your upcoming meetings</p>
    </div>
  </template>
</mgt-agenda>

I use for this the conditional rendering capability in MGT.

To show upcoming meetings, for simplicity, I use the default template provided with the Agenda component.

Animated gif showing signing in to the app with a Microsoft 365 account and viewing upcoming meetings

Summary

Microsoft Graph Toolkit is a great way to build apps that connect to Microsoft 365. It takes away the complexity of connecting to Microsoft 365 and provides a set of components that you can use to build your app and bring in the data and insights from Microsoft 365. Because MGT components are highly customizable, you can seamlessly integrate them in your app.

Run the sample app locally and see for yourself how easy it is to build apps that connect to Microsoft 365 using Microsoft Graph Toolkit.

#64 Build your first app for Microsoft 365

#64 Build your first app for Microsoft 365

Learning something new is often daunting, especially when it's something like developing for a new platform. Building for a platform comes with all kinds of specific knowledge like what tooling, SDKs, and APIs to use, how to integrate your app, and how to package and distribute it. The great thing is though, that platforms are multipliers that allow you to tap into an existing audience. Yes, you need to learn a lot to truly benefit from a platform, but the great thing is that you can start small and build your way up.

🥇 Get started

To help you get started, I recently published a tutorial that shows you how to build your first app for Microsoft 365 in under 10 minutes. Literally. This tutorial is a great place to start, either for yourself or the new developers you're onboarding in your organization.

Check it out: How to build your first app for Microsoft 365 in 10 minutes .

📆 First scenario: show upcoming meetings

After you've built your first app, you're ready to work on a simple scenario: show upcoming meetings for the signed-in Microsoft 365 user. It's not overly complex, but it teaches you a common scenario that you might need when integrating work apps with Microsoft 365.

Check out the tutorial: How to show upcoming meetings for a Microsoft 365 user.

🚀 Supercharge your app with Microsoft Graph Toolkit

Both tutorials use the Microsoft Graph JavaScript SDK which gives you the most robust way to connect to the Microsoft Graph API. If you're looking for an even quicker way to integrate with Microsoft Graph, you should check out the Microsoft Graph Toolkit: a collection of web components and auth providers to connect your apps to Microsoft 365.

See how I built the upcoming meetings apps using the Microsoft Graph Toolkit.

💯 Extra!

As a subscriber to my newsletter, I'll give you a sneak peek at something I've been working on in the last few days: a single-page app connected to Microsoft 365 that allows you to find a meeting slot for a few attendees who are on Microsoft 365.

Check it out here: Find meeting times and schedule a meeting using Microsoft Graph Toolkit.

It's similar to the functionality that you get in Outlook but which you could integrate into your work apps.

The best way to learn is to run these apps and see them in action!

If you're building apps for Microsoft 365, I'd love to hear about them. Leave a comment and I'm looking forward to hearing from you.

Show upcoming meetings for a Microsoft 365 user

Show upcoming meetings for a Microsoft 365 user

Learn how you can build a simple personal assistant in under 10 minutes that'll show a Microsoft 365 user the meetings they have left for the day.

Show upcoming meetings for a Microsoft 365 user

Recently, I published an article on freeCodeCamp that shows you how you can build in just 10 minutes a simple personal assistant that shows upcoming meetings for the signed-in user.

Browser window with a web page showing upcoming meetings for a Microsoft 365 user

Showing upcoming meetings is a common scenario when integrating Microsoft 365 in work applications. It shows you how to get information from the user's calendar and check their availability for a particular time slot. And it's also a great way to get started with building apps on Microsoft 365.

The tutorial shows you the basics of setting up auth in a single-page app and using the Microsoft Graph JavaScript SDK to connect to the Microsoft Graph API. It also demonstrates working with calendar views and formatting dates.

Give it a try, and I'm looking forward to hearing what you think.

Reference sample: Single Page App connected to Microsoft 365

Reference sample: Single Page App connected to Microsoft 365

When building apps connected to Microsoft 365, before you can bring in data from Microsoft 365, you need to set up authentication. Here's a reference sample of a Single Page App that shows how to do that.

Work apps need work data

Microsoft 365 is a popular set of applications that organizations across the world use to facilitate collaboration and communications. It's also a platform that you can use to build apps for work and streamline how people work together.

Types of apps that you can build on Microsoft 365 grouped into extensions and custom apps

These apps can show up inside Microsoft 365, bringing information from line of business systems into the apps that people use every day. They can also be standalone web-, desktop-, and mobile apps that combine data and insights from Microsoft 365 with data from other systems.

No matter which type of app you choose to build, you need to start with connecting to Microsoft 365, which means you need to set up authentication.

Reference sample: Single Page App connected to Microsoft 365

Because you can build many types of apps connected to Microsoft 365, there are many ways to set up authentication. And if you're just starting building apps for Microsoft 365, it might not be quite clear for you what it is exactly you need and how to combine the different parts together.

To help you get started, I built a sample Single Page Application that shows you how to:

  • setup authentication with Microsoft 365 in a Single Page Application
  • let users sign in and -out with their Microsoft 365 accounts to your app
  • retrieve data from Microsoft 365 using Microsoft Graph
  • register your app with the Microsoft identity platform

The sample app is built using plain JavaScript, which lets you reuse the code in any JavaScript framework. In the repo, you'll find the app built in two ways, using immediately invoked function expressions (IIFE) and using ES modules (ESM). It's largely a matter of preference which one you choose to use, but I wanted to show you both approaches.

If you want to see how I built the app step by step, check out my recent article on freeCodeCamp.

❌
❌