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.
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
- 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") ); }
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
// 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.
- 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.
- For each of the selected teams you need to fetch the unique membership ID
- 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)
Did you find this article usefull? Follow me on twitter to be notified when I publish something new!
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