Thursday, 20 October 2016

Working with the CSOM External Sharing API in SharePoint Online

I was recently working on a SharePoint Online project where we had quite a heavy use of the External Sharing CSOM API.

Here are some utility functions I have put together which might be useful in the future.

I have used the SharePoint Online CSOM version 16.1.5626.1200 for this:
https://www.nuget.org/packages/Microsoft.SharePointOnline.CSOM/16.1.5626.1200/

Also, there are some really nice samples in SharePoint Patterns and Practices (PnP) around External Sharing

1) Site Collection External Sharing

2) External Sharing Expiration Service

In my case however, I have used the native CSOM API methods for creating the utility functions.

1) Get Externally Shared Documents


This method uses search to get all documents which are externally shared. You can modify the search query to filter by site, site collection, document library etc.

string siteUrl = "https://yourtenant.sharepoint.com/sites/teamsite";
string userName = "user@yourtenant.onmicrosoft.com";
string userPassword = "password";
using (var clientContext = new ClientContext(siteUrl))
{
var passWord = new SecureString();
foreach (char c in userPassword.ToCharArray()) passWord.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, passWord);
var keywordQuery = new KeywordQuery(clientContext);
//All externally shared documents.
keywordQuery.QueryText = "ViewableByExternalUsers=TRUE contentclass:STS_ListItem_DocumentLibrary";
keywordQuery.TrimDuplicates = false;
var searchExecutor = new SearchExecutor(clientContext);
var results = searchExecutor.ExecuteQuery(keywordQuery);
clientContext.ExecuteQuery();
var resultRows = results.Value[0].ResultRows.ToList();
foreach (var resultRow in resultRows)
{
Console.WriteLine(resultRow["OriginalPath"]);
}
}


2) Get external users for a document


This method uses the native CSOM API to get all the users with whom a particular document is shared.

string siteUrl = "https://yourtenant.sharepoint.com/sites/teamsite";
string userName = "user@yourtenant.onmicrosoft.com";
string userPassword = "password";
string fullDocumentUrl = "https://yourtenant.sharepoint.com/sites/teamsite/Shared%20Documents/my_sample_document.pptx";
using (var clientContext = new ClientContext(siteUrl))
{
var passWord = new SecureString();
foreach (char c in userPassword.ToCharArray()) passWord.AppendChar(c);
clientContext.Credentials = new SharePointOnlineCredentials(userName, passWord);
ObjectSharingSettings info = Web.GetObjectSharingSettings(clientContext, fullDocumentUrl, 0, true);
ObjectSharingInformationUserCollection sharedUsers = info.ObjectSharingInformation.SharedWithUsersCollection;
//Only get external users. For each user, only get their login names. Modify as required.
clientContext.Load(sharedUsers, su => su.Where(user => user.IsExternalUser == true).Include(user => user.LoginName));
clientContext.ExecuteQuery();
foreach (var user in sharedUsers)
{
Console.WriteLine(user.LoginName);
}
}

3) Get all external users in a Site Collection:


string tenantAdminUrl = "https://yourtenant-admin.sharepoint.com/";
string userName = "user@yourtenant.onmicrosoft.com";
string userPassword = "password";
string siteCollectionUrl = "https://yourtenant.sharepoint.com/sites/teamsite/";
//Open the Tenant Administration Context with the Tenant Admin Url
using (var tenantContext = new ClientContext(tenantAdminUrl))
{
//Authenticate with a Tenant Administrator
var passWord = new SecureString();
foreach (char c in userPassword.ToCharArray()) passWord.AppendChar(c);
tenantContext.Credentials = new SharePointOnlineCredentials(userName, passWord);
var o365Tenant = new Office365Tenant(tenantContext);
//initalize varables to going through the paged results
int position = 0;
bool hasMore = true;
while (hasMore)
{
//get external users 50 at a time (this is the limit and why we are paging)
var externalUsers = o365Tenant.GetExternalUsersForSite(siteCollectionUrl, position, 50, String.Empty, SortOrder.Descending);
tenantContext.Load(externalUsers, i => i.TotalUserCount);
tenantContext.Load(externalUsers, i => i.ExternalUserCollection);
tenantContext.ExecuteQuery();
//convert each external user to our own entity
foreach (var extUser in externalUsers.ExternalUserCollection)
{
position++;
Console.WriteLine(extUser.DisplayName + " " + extUser.UniqueId + " " +
extUser.AcceptedAs + " " + extUser.InvitedAs + " " + extUser.InvitedBy + extUser.WhenCreated);
}
//determine if we have more pages to process
hasMore = (externalUsers.TotalUserCount > position);
}
}

4) Get all external users in a Tenant:


string tenantAdminUrl = "https://yourtenant-admin.sharepoint.com/";
string userName = "user@yourtenant.onmicrosoft.com";
string userPassword = "password";
//Open the Tenant Administration Context with the Tenant Admin Url
using (var tenantContext = new ClientContext(tenantAdminUrl))
{
//Authenticate with a Tenant Administrator
var passWord = new SecureString();
foreach (char c in userPassword.ToCharArray()) passWord.AppendChar(c);
tenantContext.Credentials = new SharePointOnlineCredentials(userName, passWord);
var o365Tenant = new Office365Tenant(tenantContext);
//initalize varables to going through the paged results
int position = 0;
bool hasMore = true;
while (hasMore)
{
//Get all external users in the tenant
var externalUsers = o365Tenant.GetExternalUsers(position, 50, String.Empty, SortOrder.Descending);
tenantContext.Load(externalUsers, i => i.TotalUserCount);
tenantContext.Load(externalUsers, i => i.ExternalUserCollection);
tenantContext.ExecuteQuery();
//convert each external user to our own entity
foreach (var extUser in externalUsers.ExternalUserCollection)
{
position++;
Console.WriteLine(extUser.DisplayName + " " + extUser.UniqueId + " " +
extUser.AcceptedAs + " " + extUser.InvitedAs + " " + extUser.InvitedBy + extUser.WhenCreated);
}
//determine if we have more pages to process
hasMore = (externalUsers.TotalUserCount > position);
}
}
Hope this helps!