Skip to content
Skip to content
Menu
A cup of dev
  • Home
  • About
  • Contact
  • Books and ink
A cup of dev

Microsoft Graph Magic: Simplifying User Removal from teams in Microsoft Teams

By Eli H. Schei on Friday, 22 March 2024, 7:00Wednesday, 13 November 2024, 10:37

If you’re a manager (or any other role) handling user access accross multiple teams in Microsoft Teams, you’ve probably groaned at how time-consuming it can be. One of my clients certainly di – with 20-30 projects going on at once, each having their own Team, removing a user who could be in any of them meant manually digging through all 30 teams to remove the user(s).

That’s why we decided to create a handy app simplifying user removal from teams. The app lets managers search for users by email, see which teams they’re (both) a member of, and easily kick them out of the necessary teams.

In this blog post, I’ll walk you through using Microsoft Graph to do just that—fetch teams, sift through them, batch the removal requests, and remove users from multiple teams all at once.

Prerequesites:I’ll assume you have a basic grasp of Microsoft Graph and app development. I won’t delve into building the entire app; rather, I’ll focus on how to use MS Graph for effective user management. Prior knowledge of concepts like authentication, API endpoints, and batch requests in Microsoft Graph will be helpful for following along.

Table of contents

  • Get the teams a user is a member of
  • Get the membership ID for each team the user will be removed from
    • What is a batch request
    • Retrieving membership IDs
  • Remove the user from selected teams
  • Summary
  • Resources

Get the teams a user is a member of

To identify the teams a user belongs to, you have two options. You can utilize the “user/{userid}/teamwork/associatedTeams” endpoint. Alternatively, for the current user, you can employ the “/me/memberOf” endpoint to retrieve all groups and then filter based on the “resourceProvisioningOptions” property.

const getUserTeams = async (userEmail: string) => {
    const currentUserTeams = await fetch(`https://graph.microsoft.com/v1.0/users/${userEmail}/teamwork/associatedTeams`, {
      method: "GET",
      headers: {
        Authorization: "Bearer " + getToken(),
        "Content-Type": "application/json",
      },
    })
      .then((response) => response.json())
      .then((data) => {
        if (data.value) {
            return data.value,
        } else {
          return data
        }
      })
      .catch((error) => {
        return error
      });
    return currentUserTeams;
  }

//For current user you can also use /me/memberOf
const getCurrentUsersTeams = async () => {
   const allGroups = await fetch(`https://graph.microsoft.com/me/memberOf`, {
     ... //shortened for readability
   }
   // Filter on resourceProvisioningOptions
  const currentUsersTeams = allGroups.filter((team) =>
    team["resourceProvisioningOptions"]?.includes("Team")
  );

}
Note: In the example provided, I’ve used the user’s email as {userid} in the Graph request. However, depending on the tenant setup, this approach might not be universally applicable. Specifically, for external users/guest users, this method won’t function as expected. External users can use their own e-mail for login – and that is what is often provided in the app-context as well. Typically in the format guestname@guestdomain.com. However, their principal name differs, often appearing as guestname_guestdomain.com#EXT#@yourdomain.onmicrosoft.com. Thus, if your application manages guest users as well, it’s essential to accommodate these variations in the code.

In your app, let the manager select which of these teams the user should be removed from – and collect the Team IDs in an array that will be used in the next step.

Get the membership ID for each Team the user will be removed from

To remove a user from a team, you require their unique membership ID for each team. To obtain this, we’ll initiate a batch request containing multiple requests to retrieve the membership ID for the selected teams.

What is a Batch Request?

A batch request is dispatched as a POST request to the https://graph.microsoft.com/v1.0/$batch endpoint. It anticipates an array containing objects structured as follows:

{
  "requests": [
    {
      "id": "1",
      "method": "GET",
      "url": "/me/drive/root:/{file}:/content"
    },
    {
      "id": "2",
      "method": "GET",
      "url": "/me/planner/tasks"
    },
....


Note: There’s a cap of 20 requests per batch. Consequently, the apps user interface incorporates restrictions preventing users from selecting more than 20 teams simultaneously.

Retrieving Membership IDs

The getUserMembershipIDs function accepts two parameters: teamIDs which represents the ID of each team from which the user should be removed, and the user’s email to locate the corresponding membership ID.

const getUserMembershipIDs = async (
  teamIDs: Array<string>,
  userEmail: string
) => {

Next, we require an empty array to store the objects intended for the batch request.

// Create empty list to keep the objects needed for the batch request
  let allUserMembershipIDRequests = [];

Then we’ll iterate through the teamIDs and generate a request object for each of them. Each ID in every batch object has to be unique. And since we need to correlate the teammembershipID with its respective team, we’ll utilize the teamID as the identifier.

for (let i = 0; i < teamIDs.length; i++) {
        //Add request object to array
        allUserMembershipIDRequests.push({
          id: teamIDs[i],
          method: "GET",
          url: `/teams/${teamIDs[i]}/members`,
        });
}

Now we are ready to actually do the batch request to collect the membership ID’s

Authentication: When doing request directly against graph you need a valid Bearer token to go with it. I’ve previously written a blogpost on Create an azure function for authentication with Microsoft Authentication Library (MSAL), using node and TypeScript. Or you could use a “wrapper” that handles the auth for you like PnPjs Graph package.
// Create string for the entire batch
  const batcContent = `{"requests":${JSON.stringify(allMembershipIDs)}}`;

 // Doing the POST request to the batch endpoint 
  const secondBatchRequestIbject = await fetch(
    "https://graph.microsoft.com/v1.0/$batch",
    {
      method: "POST",
      headers: {
        //You need a valid bearer token
        Authorization: "Bearer " + getToken(),
        "Content-Type": "application/json",
      },
      body: batcContent,
    }
  )
    .then((response) => response.json())
    .then((data) => {
      ... //handle response here
    }).catch((error) => {
      return error;
    });
};

Within the .then((data) => {}) function, you’ll need to iterate through all the responses, extract the array containing all the membership IDs for each team and isolate the membership ID corresponding to the user you’re targeting. And then put the required information for the subsequent batch request into an array, and return this array.

       // You get multiple responses back and need to filter out the membershipID for the user you are removing  
      const results = data.responses;

      // Array to contain the information needed to do the next request
      let tmp = [];

      //checking if the response is not empty
      if (results && results.length) {

        // loopint through results and filtering the members of each team to find the unique memberID of the user
        for (let i = 0; i < results.length; i++) {
          // Filtering on the userEmail that was sent in as a parameter
          const usermemberid = results[i].body.value.filter(
            (user) => (user.email as string).toLowerCase() === userEmail.toLowerCase()
          );

          // Creating a temporary object with the information needed for next request
          const tmpObj = {
            teamId: results[i].id,
            membershipID: usermemberid[0].id,
            useremail: userEmail,
          }
          //Adding obj to array
          tmp.push(tmpObj);
        }
      }
      return tmp;

Remove the user from selected teams

Now, let’s put it all together and proceed to remove users.

The deleteUserFromTeam function shares the same parameters as the getUserMembershipIDs function. This function is triggered from the user interface when they click the “Remove from teams” button.

The initial step involves invoking the getUserMembershipIDs function described abowe to gather all the membership IDs and store this information in a variable named batchQueriesInfo.

export const deleteUserFromTeam = async (
  useremail: string,
  teamsIds: string
) => {
  let batchQueriesInfo = await getUsersMemberIDs(
    teamsIds,
    useremail
  );

Next, we iterate through this variable and generate the objects that will be included in the subsequent batch request.

 let deleteMembershipBatch = [];
  for (let i = 0; i < batchQueriesInfo.length; i++) {
    deleteMembershipBatch.push({
      id: batchQueriesInfo[i].teamId,
      method: "DELETE",
      // the endpoint url needs both the Team ID and the membershipID
      url: `/teams/${batchQueriesInfo[i].teamId}/members/${batchQueriesInfo[i].membershipID}`,
    });
  }

Once the objects are crafted, we can proceed with the final batch call, resulting in the removal of the user from the teams.

const batcContent = `{"requests":${JSON.stringify(deleteMembershipBatch)}}`;

  const batchRequestToDeleteUser = await fetch(
    "https://graph.microsoft.com/v1.0/$batch",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer " + getToken(),
        "Content-Type": "application/json",
      },
      body: batcContent,
    }
  )
    .then((response) => response.json())
    .then((data) => {
      return data;
    });

And thats it. You could (and should) send the batch response back to the app to notify if the deletion requests was successfull or not.

Summary

This blogpost covers how to use Microsoft Graph to remove a user from teams.

  1. You need a list of teamIDs and the users e-mail. In my example this is not shown, but it is collected within the user interface of the app.
  2. For each of the selected teams you need to fetch the unique membership ID
  3. Use this information + the teams ID to create a batch request to remove the user from the teams.

Remember to stick to a 20-request limit per batch to stay within bounds.

Resources

  • Batching in Microsoft Graph (Microsoft docs)
  • Create an azure function for authenticating with MSAL using node and TypeScript (Blogpost)
  • PnPJs Graph package (PnPjs docs)
  • Repo with source code used in this blogpost (GitHub)
  • Remove member from team (Microsoft docs)

If you are interested in Microsoft 365 Development you might also like my other blogposts in this category.

Also, if you have any feedback or questions, please let me know in the comments below. 🙂

Thank you for reading, and happy coding!

/Eli

If you want to support my content you can

Share this:

  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on X (Opens in new window) X

Post navigation

How to leverage teams-js in your Teams app; Working with user context and SharePoint site context
Give your app granular permissions to a specific site or list in SharePoint

Leave a ReplyCancel reply

Eli H. Schei

I'm a front-end developer who mainly work in the Microsoft 365-sphere. As a developer I read a lot of blogs. And in my experience I can read multiple different blogposts about exactly the same topic, and only one of them makes sense to me. Therefore I’m adding my voice to the mix, and hopefully one of my blogposts will be the one that makes sense of a topic for you. You can learn more about me here.

Recent Posts

  • React in ListViewCommandSet – how to fix the “Cannot read properties of undefined (reading ‘id’)” error
  • How to Get Site-ID with Graph Explorer (and other SharePoint info)
  • How to use Azure CLI to deploy Azure Functions: Step-by-Step Guide
  • Give your app granular permissions to a specific site or list in SharePoint
  • Microsoft Graph Magic: Simplifying User Removal from teams in Microsoft Teams

Categories

  • Azure
    • Azure CLI
    • Azure functions
  • Level
    • Beginner
    • Intermediate
  • Microsoft 365 Development
    • Microsoft Authentication Library
    • Microsoft Graph
    • Microsoft Teams
    • PNP powershell
    • PowerApps
      • PowerApps Component Framework
    • SharePoint Framework
    • SharePoint Online
  • Tech Lead
  • Web development
    • Accessibility
    • Soft skills
    • Tips and tricks

Tags

accessibility app permissions ARIA azure Azure CLI azure functions Content creation custom themes favorites git github ListViewCommandSet M365 CLI M365 development MS Graph PCF PnPjs PnP powershell power apps PowerApps Component Framework quicktip react resources SharePoint Online Sideloading SPfx Teams teams app dev Teams apps Tech lead tools wcag webdev Windows terminal
©2025 A cup of dev | WordPress Theme by SuperbThemes.com