Prevent a group of user access Shared Document using csom - sharepoint

I want to prevent a group of user in sharepoint (Ex: Member) having access to "Shared Documents" by using csom.
However, It doesn't work when I excute my code (The account which are in the group i mention above still have access in my site.
There is my code:
ClientContext context = new ClientContext("https://example.com/sites/Litware");
SecureString password = new SecureString();
foreach (char c in "abcd".ToCharArray()) password.AppendChar(c);
context.Credentials = new SharePointOnlineCredentials("example#example.onmicrosoft.com", password);
var web = context.Web;
context.Load(web);
context.ExecuteQuery();
var memGroup = web.SiteGroups.GetByName("Member");
context.Load(memGroup);
var users = memGroup.Users;
context.Load(users);
context.ExecuteQuery();
foreach (var user in users)
{
Principal principal = web.EnsureUser(user.LoginName);
var folder = web.GetFolderByServerRelativeUrl("/Shared Documents");
var roleDef = context.Site.RootWeb.RoleDefinitions.GetByType(RoleType.None);
var roleBindings = new RoleDefinitionBindingCollection(context) { roleDef };
folder.ListItemAllFields.BreakRoleInheritance(true, false);
folder.ListItemAllFields.RoleAssignments.Add(principal, roleBindings);
}
So where did I get it wrong and how to solve it?

Please refer the following code:
Folder folder = ctx.Web.GetFolderByServerRelativeUrl("/sites/dev/shared%20documents");
ctx.Load(folder);
ctx.Load(folder.ListItemAllFields);
ctx.ExecuteQuery();
Group groupToRemove = ctx.Web.SiteGroups.GetByName("dev Members");
ctx.Load(groupToRemove);
ctx.ExecuteQuery();
folder.ListItemAllFields.BreakRoleInheritance(true, false);
folder.ListItemAllFields.RoleAssignments.GetByPrincipal(groupToRemove).DeleteObject();
ctx.ExecuteQuery();
Reference:
Remove specific user permissions from one folder in Sharepoint online with powershell

Related

Create Folder and Share with Guest User without Microsoft Account in Sharepoint with CSOM

I am quite new in CSOM/Sharepoint development and have an interesting task to solve. Unfortunately I don't make as much progress with some details as I would like.
A customer of mine wants a secure way to exchange confidential documents. Therefore my idea was to create a folder in Sharepoint for each customer and to share it with the customer as a guest user. So the customer has access to "his" document folder and can upload and download documents there. I can do this manually as well, but I would like to solve this programmatically via CSOM.
The programmatic creation of the folder I have managed so far. Also the file upload is no problem.
However, the release of the folder of the customer is problematic. I managed to share the folder so that the customer can log in with his Microsoft account or that the order is released "for everyone".
What I need is a personal release WITHOUT forcing an MS account. An personal link with verification code etc...
This is my code so far.
public static void CreateAndShareFolder(ClientContext context, string folderName, string userEmail)
{
var listTitle = "Dokumente";
var rootFolder = "Testfolder_ROOT/";
var folder = CreateFolder(context.Web, listTitle, rootFolder + folderName);
var users = new List<UserRoleAssignment>();
users.Add(new UserRoleAssignment()
{
UserId = userEmail,
Role = Role.Edit,
});
var serverRelativeUrl = folder.ServerRelativeUrl;
var absoluteUrl = new Uri(context.Url).GetLeftPart(UriPartial.Authority) + serverRelativeUrl;
/* User gets Email, but with "public" Sharing-Link */
//var userSharingResults = DocumentSharingManager.UpdateDocumentSharingInfo(context, absoluteUrl, users, true, true, true, null, true, true);
/* User gets Email, but needs an MS-Account to View */
var userSharingResults = DocumentSharingManager.UpdateDocumentSharingInfo(context, absoluteUrl, users, false, false, true, null, false, true);
context.ExecuteQuery();
}
// From Stackoverflow: https://stackoverflow.com/a/22010815/3062062
public static Folder CreateFolder(Web web, string listTitle, string fullFolderUrl)
{
if (string.IsNullOrEmpty(fullFolderUrl))
throw new ArgumentNullException("fullFolderUrl");
var list = web.Lists.GetByTitle(listTitle);
return CreateFolderInternal(web, list.RootFolder, fullFolderUrl);
}
private static Folder CreateFolderInternal(Web web, Folder parentFolder, string fullFolderUrl)
{
var folderUrls = fullFolderUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string folderUrl = folderUrls[0];
var curFolder = parentFolder.Folders.Add(folderUrl);
web.Context.Load(curFolder);
web.Context.ExecuteQuery();
if (folderUrls.Length > 1)
{
var subFolderUrl = string.Join("/", folderUrls, 1, folderUrls.Length - 1);
return CreateFolderInternal(web, curFolder, subFolderUrl);
}
return curFolder;
}

Is it possible to manipulate master page content (Remove certain code programmatically )in share point 2013 using csom

I am trying to remove a piece of code from sharepoint master page from a lot of sites,so is it possible to manipulate the master page content using csom.
As a workaround, get the master page from Master Page Gallery using CSOM, modify the file and replace some content in the file, then set master page using this:
web.CustomMasterUrl = masterUrl;
Articles:
Set Custom Master Page through CSOM SharePoint
C# Search/Replace in Files
var rootWeb = clientContext.Site.RootWeb;
clientContext.Load(rootWeb);
clientContext.ExecuteQuery();
string CustomMasterPage = rootWeb.CustomMasterUrl;
var masterPagefile = rootWeb.GetFileByServerRelativeUrl(CustomMasterPage);
var stream = masterPagefile.OpenBinaryStream();
clientContext.Load(masterPagefile);
clientContext.ExecuteQuery();
if (masterPagefile.CheckOutType == CheckOutType.None)
{
using (var reader = new StreamReader(stream.Value, Encoding.UTF8))
{
masterPageContent = reader.ReadToEnd();
}
masterPagefile.CheckOut();
clientContext.ExecuteQuery();
var catalog = clientContext.Site.GetCatalog((int)ListTemplateType.MasterPageCatalog);
var files = catalog.RootFolder.Files;
clientContext.ExecuteQuery();
var fileCreationInformation = new FileCreationInformation();
fileCreationInformation.Content = Encoding.UTF8.GetBytes(masterPageContent);
fileCreationInformation.Overwrite = true;
fileCreationInformation.Url = rootWeb.CustomMasterUrl;
files.Add(fileCreationInformation);
clientContext.ExecuteQuery();
masterPagefile.CheckIn(" Test", CheckinType.MinorCheckIn);
clientContext.ExecuteQuery();
}

(401) Unauthorized exception while downloading file from SharePoint

I have generated an access token using OAuth mechanism for SharePoint Online server. I am using this token to create ClientContext using CSOM. While I am able to access all the sites, libraries, and folders seamlessly, I get error
The remote server returned an error: (401) Unauthorized.
while downloading the file from SharePoint Online. Below is the code that I am using for file download:
var clientContext = TokenHelper.GetClientContextWithAccessToken("https://adventurer.sharepoint.com/Subsite1", accessToken);
var list = clientContext.Web.Lists.GetByTitle("SubSite 1 Library 1");
string vquery = #"<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='UniqueId' /><Value Type='Lookup'>" + "6718053d-a785-489c-877f-5a4b88dcb2a7" + "</Value></Eq></Where></Query></View>";
CamlQuery query = new CamlQuery();
query.ViewXml = vquery;
var listItems = list.GetItems(query);
clientContext.Load(listItems, items => items.Take(1).Include(item => item.File));
clientContext.ExecuteQuery();
var fileRef = listItems[0].File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
I don't understand the root cause of this error, as I am passing client context with right access token. I want to know if OpenBinaryDirect has a limitation to work with access tokens? If not, what is wrong with above code? Is there any other alternative that can be used to download using access token?
After trying a lot of alternatives, I have come to conclusion that OpenBinaryDirect() cannot be used with OAuth tokens. I was able to download file from SharePoint Online using two other approaches. I am posting the answers here so that it might help someone:
Approach 1 (OpenBinaryStream):
var file = clientContext.Web.GetFileByServerRelativeUrl(fileRef);
clientContext.Load(file);
clientContext.ExecuteQuery();
ClientResult<Stream> streamResult = file.OpenBinaryStream();
clientContext.ExecuteQuery();
While this approach works perfectly, OpenBinaryStream is not available in Microsoft.SharePoint.Client.dll <= v 14.0.0.0.
Approach 2 (WebClient or Other Http Requests):
string downloadUrl = HostURL + "/_api/web/getfilebyserverrelativeurl('" + fileRef + "')/$value";
WebClient client = new WebClient();
client.Headers.Add("Authorization", "Bearer " + accessToken);
client.DownloadFile(downloadUrl, filePath);
Note the download URL that I have used for WebClient. Normal file URL will not work to download files from SharePoint Online.
I am using C# and here is how I am currently retrieving documents from SharePoint Online. I am showing the user a list of their documents in a gridview, so I populate a DataTable with the documents. I am unsure of a way using an Access Token, but if you are able to use a Service Account like I am, then hopefully this helps you.
Namespaces
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
Object Attributes
SecureString securePassword = new SecureString();
private string username = "";
ClientContext context = new SP.ClientContext("https://<root>.sharepoint.com/<site collection (unless root)>/<site>");
Constructor (This is how I am authenticating)
public SharePoint()
{
securePassword = convertToSecureString(System.Web.Configuration.WebConfigurationManager.AppSettings["O365PW"]);
username = System.Web.Configuration.WebConfigurationManager.AppSettings["O365UN"];
context.Credentials = new SharePointOnlineCredentials(username, securePassword);
}
Method to get documents
public DataTable GetDocuments(int changeID)
{
DataTable dt = new DataTable("ChangeDocuments");
DataRow dr = dt.NewRow();
dt.Columns.Add("Title");
dt.Columns.Add("URL");
dt.Columns.Add("ChangeID");
dt.Columns.Add("Modified");
dt.Columns.Add("ID");
// The SharePoint web at the URL.
Web web = context.Web;
// We want to retrieve the web's properties.
context.Load(web);
// We must call ExecuteQuery before enumerate list.Fields.
context.ExecuteQuery();
// Assume the web has a list named "Announcements".
SP.List oList = context.Web.Lists.GetByTitle("Name of your document library");
// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
// so that it grabs all list items, regardless of the folder they are in.
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
query.ViewXml = "<View><Query><Where><Eq><FieldRef Name='ChangeID'/>" +
"<Value Type='Number'>" + changeID + "</Value></Eq></Where></Query><RowLimit>100</RowLimit></View>";
SP.ListItemCollection items = oList.GetItems(query);
// Retrieve all items in the ListItemCollection from List.GetItems(Query).
context.Load(items);
context.ExecuteQuery();
foreach (Microsoft.SharePoint.Client.ListItem listItem in items)
{
// We have all the list item data. For example, Title.
dr = dt.NewRow();
dr["Title"] = listItem["FileLeafRef"];
if (String.IsNullOrEmpty(listItem["ServerRedirectedEmbedUrl"].ToString()))
{
dr["URL"] = "<root>/<site>/<document library>" + listItem["FileLeafRef"].ToString();
}
else
{
dr["URL"] = listItem["ServerRedirectedEmbedUrl"];
}
dr["ChangeID"] = listItem["ChangeID"];
dr["Modified"] = Convert.ToDateTime(listItem["Modified"]).ToString("MMM.dd,yyyy h:mm tt");
dr["ID"] = listItem["ID"];
dt.Rows.Add(dr);
}
return dt;
}
Method to convert password to secure string
private SecureString convertToSecureString(string strPassword)
{
var secureStr = new SecureString();
if (strPassword.Length > 0)
{
foreach (var c in strPassword.ToCharArray()) secureStr.AppendChar(c);
}
return secureStr;
}

Multiple Querys context.Load SP O365

I need to retrieve a lot of User PersonProperties, and i was wondering if it is possible to load it all together.
For example:
var userList = web.SiteUserInfoList.GetItems(CamlQuery.CreateAllItemsQuery());
clientContext.Load(userList);
clientContext.ExecuteQuery();
PeopleManager pm = new PeopleManager(clientContext);
List<PersonProperties> users = new List<PersonProperties>();
foreach (ListItem u in userList)
{
var personProperties = pm.GetPropertiesFor(u.FieldValues["Name"].ToString());
users.Add(personProperties);
}
clientContext.Load(users); //load all users[i].UserProfileProperties and PictureUrl
clientContext.ExecuteQuery();
My app is a ProviderHosted and it is for SharePoint Online 2013
Thanks for your time.
Since SharePoint CSOM supports Request Batching you could take advantage of this feature and consider the following example that demonstrates how to submit two requests to the server in order to:
retrieve site users
retrieve profile properties for site users
Example:
//1.Load site users
var siteUsers = ctx.Web.SiteUsers;
ctx.Load(siteUsers);
ctx.ExecuteQuery();
//2.Load user profile properties for site users
var pm = new PeopleManager(ctx);
var results = new Dictionary<string,PersonProperties>();
foreach (var siteUser in siteUsers)
{
var personProperties = pm.GetPropertiesFor(siteUser.LoginName);
ctx.Load(personProperties);
results.Add(siteUser.LoginName,personProperties);
}
ctx.ExecuteQuery();
Usage
foreach (var result in results)
{
var userLoginName = result.Key;
var userProperties = result.Value;
Console.WriteLine("{0} ({1})",userLoginName, userProperties.Email);
}

Not able to fetch comments from SharePoint user profile social database

I want to fetch comments entered using SocialCommentControl from user profile social database. I tried following snippet in Managed CSOM API but could not succeed. Any help will greatly appreciated.
System.Net.NetworkCredential cred = new System.Net.NetworkCredential("domain\\useracc", "pass#word1");
ClientContext clientContext = new ClientContext("http://testsitecollection/"); clientContext.Credentials = cred;PersonProperties owner = new PeopleManager(clientContext).GetPropertiesFor("domain\\useracc");
MicrofeedManager mgr = new MicrofeedManager(clientContext);
clientContext.Load(mgr, f => f.CurrentUser);
clientContext.Load(owner);
clientContext.ExecuteQuery();
MicrofeedRetrievalOptions optn = new MicrofeedRetrievalOptions();
optn.ContentOnly = true;
optn.IncludedTypes = MicroBlogType.All;
optn.ResultSortOrder = MicrofeedSortOrder.CreatedTime;
optn.NewerThan = DateTime.Today.AddDays(-2);
ClientResult<MicrofeedThreadCollection> res = mgr.GetMyConsolidatedFeed(optn);
clientContext.ExecuteQuery();

Resources