Skip to main content
This guide covers operations for working with groups in Microsoft Graph, including creating groups, managing members, and working with group resources.

Group Types

Microsoft Graph supports several group types:
  • Microsoft 365 Groups - Collaborative groups with shared resources
  • Security Groups - Used for access control
  • Distribution Groups - Email distribution lists
  • Mail-Enabled Security Groups - Combined email and security features

Getting Started

using Microsoft.Graph;
using Microsoft.Graph.Models;

var graphClient = new GraphServiceClient(authProvider);

Listing Groups

Get All Groups

var groups = await graphClient.Groups
    .GetAsync();

foreach (var group in groups.Value)
{
    Console.WriteLine($"{group.DisplayName} - {group.GroupTypes}");
}

Filter Groups

var m365Groups = await graphClient.Groups
    .GetAsync(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Filter = 
            "groupTypes/any(c:c eq 'Unified')";
    });

Select Specific Properties

var groups = await graphClient.Groups
    .GetAsync(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Select = new[] 
        { 
            "id",
            "displayName", 
            "mail",
            "groupTypes",
            "membershipRule"
        };
    });

Creating Groups

Create a Microsoft 365 Group

1

Define group properties

var newGroup = new Group
{
    DisplayName = "Marketing Team",
    Description = "Marketing department collaboration group",
    MailNickname = "marketing-team",
    MailEnabled = true,
    SecurityEnabled = false,
    GroupTypes = new List<string> { "Unified" },
    Visibility = "Private"
};
2

Create the group

try
{
    var createdGroup = await graphClient.Groups
        .PostAsync(newGroup);
    
    Console.WriteLine($"Created group: {createdGroup.Id}");
    Console.WriteLine($"Email: {createdGroup.Mail}");
}
catch (ODataError odataError)
{
    Console.WriteLine($"Error: {odataError.Error.Message}");
}

Create a Security Group

var securityGroup = new Group
{
    DisplayName = "IT Administrators",
    Description = "IT admin security group",
    MailNickname = "it-admins",
    MailEnabled = false,
    SecurityEnabled = true,
    GroupTypes = new List<string>()
};

var createdGroup = await graphClient.Groups
    .PostAsync(securityGroup);

Create a Dynamic Group

var dynamicGroup = new Group
{
    DisplayName = "All Engineers",
    Description = "All users in Engineering department",
    MailNickname = "all-engineers",
    MailEnabled = true,
    SecurityEnabled = true,
    GroupTypes = new List<string> { "DynamicMembership" },
    MembershipRule = "(user.department -eq \"Engineering\")",
    MembershipRuleProcessingState = "On"
};

var createdGroup = await graphClient.Groups
    .PostAsync(dynamicGroup);

Managing Group Members

Add Members

// Create reference to user
var userReference = new ReferenceCreate
{
    OdataId = $"https://graph.microsoft.com/v1.0/users/{userId}"
};

await graphClient.Groups["group-id"].Members.Ref
    .PostAsync(userReference);

Add Multiple Members at Creation

var newGroup = new Group
{
    DisplayName = "Project Alpha",
    MailNickname = "project-alpha",
    MailEnabled = true,
    SecurityEnabled = false,
    GroupTypes = new List<string> { "Unified" },
    MembersODataBind = new List<string>
    {
        $"https://graph.microsoft.com/v1.0/users/{userId1}",
        $"https://graph.microsoft.com/v1.0/users/{userId2}",
        $"https://graph.microsoft.com/v1.0/users/{userId3}"
    }
};

var createdGroup = await graphClient.Groups
    .PostAsync(newGroup);

List Group Members

var members = await graphClient.Groups["group-id"].Members
    .GetAsync();

foreach (var member in members.Value)
{
    if (member is User user)
    {
        Console.WriteLine($"User: {user.DisplayName}");
    }
    else if (member is Group group)
    {
        Console.WriteLine($"Nested Group: {group.DisplayName}");
    }
}

Remove a Member

await graphClient.Groups["group-id"]
    .Members["user-id"]
    .Ref
    .DeleteAsync();

Check Membership

var memberOf = await graphClient.Users["user-id"].MemberOf
    .GetAsync(requestConfiguration =>
    {
        requestConfiguration.QueryParameters.Filter = 
            $"id eq '{groupId}'";
    });

bool isMember = memberOf.Value.Count > 0;

Managing Group Owners

Add an Owner

var ownerReference = new ReferenceCreate
{
    OdataId = $"https://graph.microsoft.com/v1.0/users/{userId}"
};

await graphClient.Groups["group-id"].Owners.Ref
    .PostAsync(ownerReference);

List Owners

var owners = await graphClient.Groups["group-id"].Owners
    .GetAsync();

foreach (var owner in owners.Value)
{
    if (owner is User user)
    {
        Console.WriteLine($"{user.DisplayName} - {user.Mail}");
    }
}

Updating Groups

Update Group Properties

var groupUpdate = new Group
{
    DisplayName = "Marketing Team - Updated",
    Description = "Updated description",
    Visibility = "Public"
};

await graphClient.Groups["group-id"]
    .PatchAsync(groupUpdate);

Deleting Groups

Delete a Group

await graphClient.Groups["group-id"]
    .DeleteAsync();

Restore a Deleted Group

Deleted groups can be restored within 30 days.
// List deleted groups
var deletedGroups = await graphClient.Directory.DeletedItems
    .GraphGroup
    .GetAsync();

// Restore a group
await graphClient.Directory.DeletedItems
    .GraphGroup["group-id"]
    .Restore
    .PostAsync(new RestorePostRequestBody());

Working with Group Resources

Access Group Calendar

// Get group calendar events
var events = await graphClient.Groups["group-id"]
    .Calendar
    .Events
    .GetAsync();

// Create a group event
var newEvent = new Event
{
    Subject = "Team Meeting",
    Start = new DateTimeTimeZone
    {
        DateTime = "2024-03-15T10:00:00",
        TimeZone = "Pacific Standard Time"
    },
    End = new DateTimeTimeZone
    {
        DateTime = "2024-03-15T11:00:00",
        TimeZone = "Pacific Standard Time"
    }
};

await graphClient.Groups["group-id"]
    .Calendar
    .Events
    .PostAsync(newEvent);

Access Group Drive

// Get group drive
var drive = await graphClient.Groups["group-id"]
    .Drive
    .GetAsync();

// List files in root
var items = await graphClient.Groups["group-id"]
    .Drive
    .Root
    .Children
    .GetAsync();

foreach (var item in items.Value)
{
    Console.WriteLine($"{item.Name} - {item.Size} bytes");
}

Advanced Scenarios

Get Groups with Transitive Members

var members = await graphClient.Groups["group-id"]
    .TransitiveMembers
    .GetAsync();

Check Member Groups for a User

var requestBody = new CheckMemberGroupsPostRequestBody
{
    GroupIds = new List<string>
    {
        "group-id-1",
        "group-id-2",
        "group-id-3"
    }
};

var memberGroups = await graphClient.Users["user-id"]
    .CheckMemberGroups
    .PostAsync(requestBody);

foreach (var groupId in memberGroups.Value)
{
    Console.WriteLine($"User is member of: {groupId}");
}

Complete Example

using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Graph.Models.ODataErrors;

public class GroupManager
{
    private readonly GraphServiceClient _graphClient;

    public GroupManager(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }

    public async Task<Group> CreateTeamGroupWithMembersAsync(
        string displayName,
        string description,
        List<string> memberIds,
        List<string> ownerIds)
    {
        try
        {
            // Prepare member references
            var memberReferences = memberIds
                .Select(id => $"https://graph.microsoft.com/v1.0/users/{id}")
                .ToList();

            // Prepare owner references (owners must also be members)
            var ownerReferences = ownerIds
                .Select(id => $"https://graph.microsoft.com/v1.0/users/{id}")
                .ToList();

            // Ensure all owners are also in members list
            memberReferences.AddRange(
                ownerReferences.Except(memberReferences)
            );

            // Create group
            var newGroup = new Group
            {
                DisplayName = displayName,
                Description = description,
                MailNickname = displayName.Replace(" ", "-").ToLower(),
                MailEnabled = true,
                SecurityEnabled = false,
                GroupTypes = new List<string> { "Unified" },
                Visibility = "Private",
                MembersODataBind = memberReferences,
                OwnersODataBind = ownerReferences
            };

            var createdGroup = await _graphClient.Groups
                .PostAsync(newGroup);

            Console.WriteLine($"Created group: {createdGroup.DisplayName}");
            Console.WriteLine($"Group ID: {createdGroup.Id}");
            Console.WriteLine($"Email: {createdGroup.Mail}");

            return createdGroup;
        }
        catch (ODataError error)
        {
            Console.WriteLine($"Error creating group: {error.Error.Message}");
            throw;
        }
    }

    public async Task<List<User>> GetAllMembersAsync(string groupId)
    {
        var allMembers = new List<User>();
        
        var members = await _graphClient.Groups[groupId].Members
            .GetAsync();

        // Handle pagination
        var pageIterator = PageIterator<DirectoryObject, DirectoryObjectCollectionResponse>
            .CreatePageIterator(
                _graphClient,
                members,
                (member) =>
                {
                    if (member is User user)
                    {
                        allMembers.Add(user);
                    }
                    return true;
                }
            );

        await pageIterator.IterateAsync();

        return allMembers;
    }
}

Next Steps

Build docs developers (and LLMs) love