Wednesday, 30 August 2017

Get all files from a SharePoint Document Library using CSOM

In this post, I am going to write CSOM based C# code to retrieve all files in a SharePoint library using Client-side Object Model. Using this CSOM code you can easily fetch all the files from document library even it has files more than List View Threshold limit.

The List View Threshold defines the maximum limit to retrieve a number of documents in a single request. By default this limit is set to 5000 rows, and in OneDrive for Business (ODFB) this limit is 20000. So any library with more than 5000 files will return an error (Ex: The number of items in this list exceeds the list view threshold, which is 5000 items).

By using CSOM, you can retrieve documents page by page by setting row limit, this will avoid the list view threshold error as we are querying only certain amount of rows in a single request.

Retrieve all documents from a SharePoint library which has more than 5000 items

The following C# code fetch all files from a SharePoint online library. It will get 100 rows in every page. You can change the row limit as per your wish. In CAML query, we are setting the view as <View Scope='RecursiveAll'>, thus gets the documents from root folder and its sub folders by recursively.
public static List<ListItem> GetAllDocumentsInaLibrary()
{
    List<ListItem> items = new List<ListItem>();
    string sitrUrl = "https://spotenant.sharepoint.com/sites/yoursite";
    using (var ctx = new ClientContext(sitrUrl))
    {
        //ctx.Credentials = Your Credentials
        ctx.Load(ctx.Web, a => a.Lists);
        ctx.ExecuteQuery();

        List list = ctx.Web.Lists.GetByTitle("Documents");
        ListItemCollectionPosition position = null;
        // Page Size: 100
        int rowLimit = 100;
        var camlQuery = new CamlQuery();
        camlQuery.ViewXml = @"<View Scope='RecursiveAll'>
            <Query>
                <OrderBy Override='TRUE'><FieldRef Name='ID'/></OrderBy>
            </Query>
            <ViewFields>
                <FieldRef Name='Title'/><FieldRef Name='Modified' /><FieldRef Name='Editor' />
            </ViewFields>
            <RowLimit Paged='TRUE'>" + rowLimit + "</RowLimit></View>";
        do
        {
            ListItemCollection listItems = null;
            camlQuery.ListItemCollectionPosition = position;
            listItems = list.GetItems(camlQuery);
            ctx.Load(listItems);
            ctx.ExecuteQuery();
            position = listItems.ListItemCollectionPosition;
            items.AddRange(listItems.ToList());
        }
        while (position != null);
    }           
    return items;
}

Tuesday, 29 August 2017

Get all Items from a SharePoint List using CSOM

In this article, I am going to write C# code to find all items in a SharePoint list with Client-side Object Model (CSOM). This code also solves the List View Threshold problem. The List View Threshold defines the maximum limit to retrieve a number of items in a single query call. By default this limit is set to 5000, and in OneDrive for Business this limit is 20000. So any list with more than 5000 items will return an error (Ex: The number of items in this list exceeds the list view threshold, which is 5000 items).

By using CSOM, you can retrieve list items page by page by setting row limit, this will avoid the list view threshold error as we are querying only certain amount of rows in a single query.

Retrieve all items from a SharePoint library which has more than 5000 items

The following C# based CSOM code fetch all items from a SharePoint online library. It will get 50 rows in every page. You can change the row limit as per your wish.
public static List<ListItem> GetAllListItemsInaList1()
{
    List<ListItem> items = new List<ListItem>();
    string sitrUrl = "https://spotenant.sharepoint.com/sites/yoursite";
    using (var ctx = new ClientContext(sitrUrl))
    {
        //ctx.Credentials = Your Credentials
        ctx.Load(ctx.Web, a => a.Lists);
        ctx.ExecuteQuery();

        List list = ctx.Web.Lists.GetByTitle("Documents");
        ListItemCollectionPosition position = null;
        // Page Size: 50
        int rowLimit = 50;
        var camlQuery = new CamlQuery();
        camlQuery.ViewXml = @"<View Scope='RecursiveAll'>
            <Query>
                <OrderBy Override='TRUE'><FieldRef Name='ID'/></OrderBy>
            </Query>
            <ViewFields>
                <FieldRef Name='Title'/><FieldRef Name='Modified' /><FieldRef Name='Editor' />
            </ViewFields>
            <RowLimit Paged='TRUE'>" + rowLimit + "</RowLimit></View>";
        do
        {
            ListItemCollection listItems = null;
            camlQuery.ListItemCollectionPosition = position;
            listItems = list.GetItems(camlQuery);
            ctx.Load(listItems);
            ctx.ExecuteQuery();
            position = listItems.ListItemCollectionPosition;
            items.AddRange(listItems.ToList());
        }
        while (position != null);
    }           
    return items;
}

Monday, 28 August 2017

Get Office 365 Groups in which a User is a Member using Graph Api

Office 365 Groups is developed with collaboration in mind. It becomes a base service for most of existing Office 365 tools that we use already ( like writing documents, planner plans, calendar meetings, teams chat and exchange mail), so finding which unified groups a user is a member of is inevitable in many scenarios.

The Microsoft Graph Api endpoint https://graph.microsoft.com/v1.0/me/memberOf gets and return all the groups where a current user is memberOf. But it returns not only the unified groups, it also lists security groups and dynamic groups. So, you need to apply proper filter to get only Office 365 groups using memberOf endpoint.

Retrieve Office 365 Groups in which current user is a member of

The following API returns all the unified groups in which I am member of.
https://graph.microsoft.com/v1.0/me/memberOf/$/microsoft.graph.group?$filter=groupTypes/any(a:a eq 'unified')

Find Office 365 Groups where an user is a member of

You can also use the same memberOf endpoint to retrieve all the unified groups where a specific user is a member. You need to just replace the /me/ part in the above url with the user's id /users/<user-id>/
https://graph.microsoft.com/v1.0/users/<user-id>/memberOf/$/microsoft.graph.group?$filter=groupTypes/any(a:a eq 'unified')
Note: You can call the memberOf endpoint without Admin Consent after applying unified filter and adding extra parameter (/$/microsoft.graph.group?$filter=groupTypes/any(a:a eq 'unified')) in memberOf endpoint url. If you call without this filter, you will receive the following Access Denied error when you don't have proper admin consent.
"error": {
    "code": "Authorization_RequestDenied",
    "message": "Insufficient privileges to complete the operation.",
}

Tuesday, 22 August 2017

EWS - Create a meeting or appointment in other user calendar.

Using Exchange Web Services (EWS) managed api, we can access and add event to specific user's calendar either by delegate access or impersonation. Both methods are used in different scenario and they require different set of permissions.

A user or account that has been granted impersonation rights will have the same rights as the user whom they are impersonating. Typically, service accounts are given the ability to impersonate the mailbox owner. In that case, the impersonating account has full mailbox rights, just as the mailbox owner does.

With delegate access, the delegate can be granted more granular rights, up to and including full mailbox access. Delegate access can also be configured per folder, or per mailbox. For example, a user can grant the delegate read-only access to the Inbox, read-write access to a calendar folder, and so on. For more info : Impersonation vs Delegate Access

Before proceed, you have to download Microsoft Exchange Web Services Managed API 2.0 dll and add as reference in your C# project.

Create a meeting or appointment as a delegate in C# using EWS

You can use following C# code to create new event in any specific user's calendar. This sample assumes that the delegate user has been granted the appropriate permissions for the mailbox owner's Calendar folder.
ExchangeService exchService = new ExchangeService(ExchangeVersion.Exchange2013_SP1); 
exchService.UseDefaultCredentials = false; 
exchService.Credentials = new NetworkCredential("admin@o365domain.com", "pwd"); 
exchService.Url = new Uri("https://outlook.office365.com/Ews/Exchange.asmx"); 
exchService.PreAuthenticate = false; 
  
Appointment appointment = new Appointment(exchService); 
// Set the properties on the appointment object to create the appointment. 
appointment.Subject = "Sales Meeting"; 
appointment.Body = "Focus on pre-sale and marketing."; 
appointment.Start = DateTime.Now.AddDays(2); 
appointment.End = DateTime.Now.AddDays(2).AddHours(3); 
appointment.Location = "Room 111"; 
appointment.ReminderMinutesBeforeStart = 240; 

appointment.RequiredAttendees.Add("user3@o365domain.onmicrosoft.com"); 

// Save the meeting to the Calendar folder of the mailbox owner and send the meeting request.
// This method call results in a CreateItem call to EWS.
Folder calendar_Folder = Folder.Bind(exchService, new FolderId(WellKnownFolderName.Calendar, "user1@o365domain.com")); 
appointment.Save(calendar_Folder.Id, SendInvitationsMode.SendToNone); 

if (appointment.RequiredAttendees.Count > 0)
{
   // The appointment has attendees so send them the meeting request.
   appointment.Save(calendar_Folder.Id, SendInvitationsMode.SendToAllAndSaveCopy);
}
else
{
    // The appointment does not have attendees, so just save to calendar.
    appointment.Save(calendar_Folder.Id, SendInvitationsMode.SendToNone);
}
Please check this MSDN post : Add appointments by using Exchange impersonation to create appointment by using impersonation.

Impersonation vs Delegate Access in Exchange/Exchange Online

we can access and modify other (or specific) user's mail items, calendar events, and other exchange related objects using either by delegate access or impersonation with Exchange Web Services (EWS) Managed API. Both methods are used in different scenario and they require different set of permissions.

Impersonation is used in scenarios in which a single account needs to access many accounts (ex: service account). An application can be written to display mailbox data such as number of unread items, calendar, and so on. The application can use a dedicated service account to access multiple users’ mailboxes to display their respective data.

Delegate access is used in scenarios in which there needs to be a one-to-one relationship between users. One common application of delegate access is the sharing of calendars between users, such as when an admin manages an executive’s calendar, or a when handful of individuals working on a project need to coordinate calendars.

A user or account that has been granted impersonation rights will have the same rights as the user whom they are impersonating. Typically, service accounts are given the ability to impersonate the mailbox owner. In that case, the impersonating account has full mailbox rights, just as the mailbox owner does.

With delegate access, the delegate can be granted more granular rights, up to and including full mailbox access. Delegate access can also be configured per folder, or per mailbox. For example, a user can grant the delegate read-only access to the Inbox, read-write access to a calendar folder, and so on.

For more details, refer this article : Exchange Impersonation vs. Delegate Access

Monday, 21 August 2017

Create calendar event in Office 365 group using EWS

As Office 365 Group (Unified Group) is robustly becoming the base service for many of Office 365 features (i.e. Planner, MS Teams, etc..) managing planner team meetings and users appointment in group calendar is inevitable now. In this post, I am going to share .net based C# code to create meeting in Office 365 Group using Managed Exchange Web Services Api (EWS).

Before proceed, you have to download Microsoft Exchange Web Services Managed API 2.0 dll and add as reference in your C# project.
ExchangeService exchService = new ExchangeService(ExchangeVersion.Exchange2013_SP1); 
exchService.UseDefaultCredentials = false; 
exchService.Credentials = new NetworkCredential("admin@o365domain.com", "pwd"); 
exchService.Url = new Uri("https://outlook.office365.com/Ews/Exchange.asmx"); 
exchService.PreAuthenticate = false; 
  
Appointment appointment = new Appointment(exchService); 
// Set the properties on the appointment object to create the appointment. 
appointment.Subject = "Sales Meeting"; 
appointment.Body = "Focus on pre-sale and marketing."; 
appointment.Start = DateTime.Now.AddDays(2); 
appointment.End = DateTime.Now.AddDays(2).AddHours(3); 
appointment.Location = "Room 111"; 
appointment.ReminderMinutesBeforeStart = 240; 
appointment.RequiredAttendees.Add("user1@o365domain.onmicrosoft.co"); 
appointment.RequiredAttendees.Add("user2@o365domain.onmicrosoft.co"); 
// Bind the specified group calendar folder. 
Folder calendar_Folder = Folder.Bind(exchService, new FolderId(WellKnownFolderName.Calendar, "salesboard@o365domain.com")); 
appointment.Save(calendar_Folder.Id, SendInvitationsMode.SendToNone);
The parameter SendInvitationsMode specifies how meeting invitations to be send to its attendees. It includes following options:

  • SendToNone : Do not send meeting invitations.
  • SendOnlyToAll : Send meeting invitations to all attendees but do not save a copy of the meeting invitation in the organizer's Sent Items folder.
  • SendToAllAndSaveCopy " Send meeting invitations to all attendees and save a copy of the meeting invitation in the organizer's Sent Items folder.

Note: AFAIK, using Exchange Web Service (EWS) we can create only meeting not appointment in office 365 group.