SharePoint CSOM – Add a content type to a site and install an app

This is a small code snippet on how to add a content type to a site and how to install an app(or these days an Add-In). Notice that adding an app this way is not the recommended way. This is “cheating”, well the recommended way to add an app to a production environment is through a app catalog or a store BUT if you do need to add it for some reason through CSOM well this is the way. You could also apply the same technique to PowerShell:


private static void EnsureDeveloperFeature(ClientContext ctx)
 {
 var result = ctx.LoadQuery(ctx.Site.Features.Where(f => f.DefinitionId == DeveloperFeatureId));
 ctx.ExecuteQuery();
 if (result.Any()) return;
 var feature = ctx.Site.Features.Add(DeveloperFeatureId, true, FeatureDefinitionScope.None);
 ctx.ExecuteQuery();
 }

 private static void DeleteDeveloperFeature(ClientContext ctx)
 {
 var result = ctx.LoadQuery(ctx.Site.Features.Where(f => f.DefinitionId == DeveloperFeatureId));
 ctx.ExecuteQuery();
 if (!result.Any()) return;
 ctx.Site.Features.Remove(DeveloperFeatureId, true);
 ctx.ExecuteQuery();
 }

 private static void EnsureContentTypeAndRibbonApp(ClientContext ctxWorkspace, string administratorsEmail)
 {
 try
 {
 var contentTypeName = ConfigurationManager.AppSettings["ContentTypeName"].ToString();
 var appFullPath = ConfigurationManager.AppSettings["RibbonAppFullPath"].ToString();

 if (String.IsNullOrEmpty(contentTypeName) && String.IsNullOrEmpty(appFullPath))
 return;

 Web currentWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(currentWeb);
 

 var webContentTypes = currentWeb.ContentTypes;
 ctxWorkspace.Load(webContentTypes);
 var apps = currentWeb.GetAppInstances();
 ctxWorkspace.Load(apps);
 ctxWorkspace.ExecuteQuery();

 // Install the ribbon achieving ribbon app if the app file exists and does not exist already
 if (System.IO.File.Exists(appFullPath) && apps.SingleOrDefault(o => o.Title.Contains(ConfigurationManager.AppSettings["ArchivingRibbonAppName"].ToString())) == null)
 {
 EnsureDeveloperFeature(ctxWorkspace);
 using (var packageStream = System.IO.File.OpenRead(appFullPath))
 {
 var appInstance = ctxWorkspace.Web.LoadAndInstallApp(packageStream);
 ctxWorkspace.Load(appInstance);
 ctxWorkspace.ExecuteQuery();
 if (appInstance != null && appInstance.Status == AppInstanceStatus.Initialized)
 {
 Console.WriteLine("App was installed on:" + currentWeb.Url);
 }
 }
 DeleteDeveloperFeature(ctxWorkspace);
 }
 
 



 var contentType = webContentTypes.SingleOrDefault(o => o.Name.Contains(contentTypeName));

 if(contentType != null)
 {
 ctxWorkspace.Load(contentType);
 ctxWorkspace.ExecuteQuery();

 ListCollection lists = ctxWorkspace.Web.Lists;
 var sourceWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(sourceWeb);
 ctxWorkspace.Load(lists);
 ctxWorkspace.ExecuteQuery();

 foreach (List list in lists.Where(o => o.BaseType == BaseType.DocumentLibrary))
 {
 if (list.Hidden || list.IsApplicationList || list.IsCatalog)
 continue;
// Check for existing content types only if content type management is set to active
 if (list.ContentTypesEnabled)
 {
 var listCTs = list.ContentTypes;
 ctxWorkspace.Load(listCTs);
 ctxWorkspace.ExecuteQuery();
 if (listCTs.SingleOrDefault(o => o.Name == contentType.Name) != null)
 continue;
 }
 list.ContentTypesEnabled = true;
 list.Update();
 ctxWorkspace.ExecuteQuery();

 list.ContentTypes.AddExistingContentType(contentType);
 list.Update();
 ctxWorkspace.ExecuteQuery();
 }
 }

 
 }
 catch (Exception ex)
 {
 
 }
 }


Advertisements

Sharepoint CSOM copy (move), delete and update files from one site collection to another

 

Here is a code sample on how to copy a file from one site collection to another one. Also how to update a file uploaded in the target destination and how to remove it from the source location.


private static void CheckWorkspaceForDocumentsToBeArhieved(String workspaceURL, string recordCenterURL)
 {
 Console.WriteLine("UpdateStatusOnMetadataPageOnWorkspace");
 Uri siteUrl = new Uri(workspaceURL);
 Uri recordCenterUrl = new Uri(recordCenterURL);
 string realm = TokenHelper.GetRealmFromTargetUrl(siteUrl);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUrl.Authority, realm).AccessToken;
 using (var ctxWorkspace = TokenHelper.GetClientContextWithAccessToken(siteUrl.ToString(), token))
 {
 string realmRC = TokenHelper.GetRealmFromTargetUrl(recordCenterUrl);
 var tokenRC = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, recordCenterUrl.Authority, realm).AccessToken;
 using (var ctxWorkspaceRC = TokenHelper.GetClientContextWithAccessToken(recordCenterUrl.ToString(), token))
 {
 ListCollection lists = ctxWorkspace.Web.Lists;
 var sourceWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(sourceWeb);
 ctxWorkspace.Load(lists);
 ctxWorkspace.ExecuteQuery();

 foreach (List list in lists.Where(o => o.BaseType == BaseType.DocumentLibrary))
 {
 if (list.Hidden || list.IsApplicationList || list.IsCatalog)
 continue;

 if (!list.FieldExistsByName("Archieve") && !list.FieldExistsByName("Secret"))
 continue;

 Microsoft.SharePoint.Client.CamlQuery camlQuery = new CamlQuery();
 camlQuery.ViewXml = @"<View Scope='RecursiveAll'><Query><Where>
 <Eq>
 <FieldRef Name='Archieve' />
 <Value Type='Boolean'>1</Value>
 </Eq>
 </Where>
 <ViewFields>
 <FieldRef Name='Archieve' />
 <FieldRef Name='FileRef' />
 <FieldRef Name='Secret' />
 <FieldRef Name='LinkFilename' />
 <FieldRef Name='Title' />
 </ViewFields></Query></View>";

 var documents = list.GetItems(camlQuery);
 ctxWorkspace.Load(documents);
 ctxWorkspace.ExecuteQuery();
List<int> filesToRemove = new List<int>();

 foreach (ListItem document in documents)
 {
 
 

 var file = document.File;
 ctxWorkspace.Load(document);
 ctxWorkspace.Load(file);
 var fileStream = file.OpenBinaryStream();
 ctxWorkspace.ExecuteQuery();

 var isSecret = document.FieldValues.SingleOrDefault(o => o.Key.Contains("Secret"));

 bool isSecretDocument = false;
 if(isSecret.Value != null)
 isSecretDocument = (bool)isSecret.Value;


 FileCreationInformation fci = new FileCreationInformation();

  using (var streamReader = new MemoryStream())
 {

 fileStream.Value.CopyTo(streamReader);
 // This step is done to avoid an error with the copying the data to the target location 
 streamReader.Seek(0, System.IO.SeekOrigin.Begin);
 // This variable is used in FileCreationInformation to avoid too large files data problem. More info: https://msdn.microsoft.com/en-us/library/office/dn904536.aspx
 fci.ContentStream = streamReader;
 
 
 fci.Url = file.Name;
 fci.Overwrite = true;
 List targetLibrary = null;

 if (isSecretDocument)
 {
 targetLibrary = ctxWorkspaceRC.Web.Lists.GetByTitle("Secret");
 
 }
 else
 {

 targetLibrary = ctxWorkspaceRC.Web.Lists.GetByTitle("Public");
 }

 ctxWorkspaceRC.Load(targetLibrary);
 ctxWorkspaceRC.ExecuteQuery();
 var folder = targetLibrary.RootFolder.EnsureFolder("folder name");

 ctxWorkspaceRC.Load(folder);
 var uploadedFile = targetLibrary.RootFolder.Files.Add(fci);
 ctxWorkspaceRC.Load(uploadedFile, f => f.ListItemAllFields);
 ctxWorkspaceRC.ExecuteQuery();

 var newDocumentItemInTargetLibrary = targetLibrary.GetItemById(uploadedFile.ListItemAllFields.Id);
 ctxWorkspaceRC.Load(newDocumentItemInTargetLibrary);
 ctxWorkspaceRC.ExecuteQuery();

 newDocumentItemInTargetLibrary["field to update"] = sourceWeb.Title;
 newDocumentItemInTargetLibrary["field to update"] = sourceWeb.Description;
 newDocumentItemInTargetLibrary.Update();
if(uploadedFile.CheckOutType != CheckOutType.None)
   uploadedFile.CheckIn("custom operation", CheckinType.MajorCheckIn);
 ctxWorkspaceRC.ExecuteQuery();

 filesToRemove.Add(document.Id);
}

 }
foreach(int fileItemID in filesToRemove)
 {
 for (int x = documents.Count - 1; x >= 0; x-- )
 {
 if (documents[x].Id == fileItemID)
 {
 documents[x].DeleteObject();
 }
 }
 }
 ctxWorkspace.ExecuteQuery();

 }
 }
 }
 }

O365 CSOM Getting User profile information without possible errors

Hi,

Here is a solution for a particular problem trying to access O365 user profiles without specifying credentials which proper privileges to the user profiles. Notice that it is not enough to add permissions to your app which uses CSOM. Believe me I tried all I could think of.

With the help of a colleague of mine I got a tip to try to explicitly specify credentials. After a few tinkering and wonderin this worked. So the error message which you might get would look

User ‘some user guid data’ doesn’t exist in UPA by UPN or SID, and user with this SID was not found in AD.

Below is a code sample which retrieved encrypted credentials and passes them on the the CSOM client context. After that the code tries to get some data from the user profile.

String manager = String.Empty;
 try
 {
 
 SecureString adminPWSecure = new SecureString();

 //get the base tenant admin urls
 string tenantAdminLoginName = ConfigurationManager.AppSettings["TenantAdminLoginName"];
 string tenantAdminPassword = ConfigurationManager.AppSettings["TenantAdminPassword"];
 string tenantAdminUrl = ConfigurationManager.AppSettings["SiteCollectionRequests_TenantAdminSite"];

 if (String.IsNullOrEmpty(tenantAdminLoginName) && String.IsNullOrEmpty(tenantAdminPassword))
 return null;

 tenantAdminLoginName = EngineCommon.Hide.Decrypt(tenantAdminLoginName);
 foreach (char c in EngineCommon.Hide.Decrypt(tenantAdminPassword).ToCharArray()) adminPWSecure.AppendChar(c);


 using (ClientContext clientContext = new ClientContext(tenantAdminUrl))
 {
 clientContext.Credentials = new SharePointOnlineCredentials(tenantAdminLoginName, adminPWSecure);

 // Get the people manager instance for tenant context
 PeopleManager peopleManager = new PeopleManager(clientContext);

 var managerData = peopleManager.GetUserProfilePropertyFor(userName, "Manager");

 clientContext.ExecuteQuery();

 if (managerData != null && !String.IsNullOrEmpty(managerData.Value))
 {
 PersonProperties personProperties = peopleManager.GetPropertiesFor(managerData.Value);
 clientContext.Load(personProperties);
 clientContext.ExecuteQuery();

 manager = personProperties.Email;
 }

 }
 } catch(Exception ex)
 {
 Console.Write("Failed to get a manager info for a user: " + ex.Message + ex.StackTrace);
 }

SharePoint Online – PowerShell, CSOM and Tools

Here are some links on how to access and modify your SharePoint Online sites and data. These might come in handy to someone whom is starting with SharePoint Online:

SharePoint Online Management Shel

Index of Windows PowerShell for SharePoint Online cmdlets

Windows PowerShell for SharePoint Online reference

SharePoint Client Browser for SharePoint Online and SharePoint on-premise

SharePoint Online Client Components SDK

Check out this great link for more info on how to use these tools:

http://blogs.technet.com/cfs-file.ashx/__key/telligent-evolution-components-attachments/01-9981-00-00-03-63-30-65/sharepoint-online-administration-with-powershell.pdf

O365 CSOM – Client Side Object Model examples

Here are some examples on how to use CSOM with O365:

This is Microsofts’ link on the matter for more examples:

https://msdn.microsoft.com/en-us/library/ff798388.aspx

 

Remove SiteCollection


 var tenantAdminUri = new Uri(tenantAdminUrl);
 string realm = TokenHelper.GetRealmFromTargetUrl(tenantAdminUri);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, tenantAdminUri.Authority, realm).AccessToken;
 using (var tenantContext = TokenHelper.GetClientContextWithAccessToken(tenantAdminUri.ToString(), token))
 {
 // Set the time out as high as possible
 tenantContext.RequestTimeout = int.MaxValue;

 var tenant = new Tenant(tenantContext);

 //start the SPO operation to create the site
 SpoOperation op = tenant.RemoveSite(webUrl);
 tenantContext.Load(op, i => i.IsComplete);
 tenantContext.RequestTimeout = int.MaxValue;
 tenantContext.ExecuteQuery();

 while (!op.IsComplete)
 {
 Console.WriteLine("Waiting 30 seconds site to be provisioned");
 //wait 30seconds and try again
 System.Threading.Thread.Sleep(30000);
 op.RefreshLoad();
 tenantContext.ExecuteQuery();
 }
 }

 Updating a list item

</pre>
List list = ctx.Web.Lists.GetByTitle(ConfigurationManager.AppSettings["SiteCollectionRequests_List"]);
ListItem listItem = list.GetItemById(id);
ctx.Load(listItem);
ctx.ExecuteQuery();

statusMessage += "Your message";
listItem["StatusMessage"] = statusMessage;
listItem.Update();
list.Update();
ctx.Web.Update();
ctx.ExecuteQuery();
<pre>

Adding a new item to a list


List list = ctx.Web.Lists.GetByTitle(ConfigurationManager.AppSettings["SiteCollectionRequests_LogList"]);

 ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
 ListItem newItem = list.AddItem(itemCreateInfo);
 newItem["Title"] = title;
 newItem["url"] = workspaceURL;

 XmlSerializer xs = new XmlSerializer(typeof(WorkspacePrivileges));
 StringWriter sww = new StringWriter();
 XmlWriter writer = XmlWriter.Create(sww);
 xs.Serialize(writer, workspacePrivileges);
 String aaa = sww.ToString();

 newItem["my text field"] = sww.ToString();
 newItem.Update();
 ctx.ExecuteQuery();

Change Workspace Privileges To Read Only


Uri siteUrl = new Uri(workspaceURL);
 string realm = TokenHelper.GetRealmFromTargetUrl(siteUrl);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUrl.Authority, realm).AccessToken;
 using (var ctxWorkspace = TokenHelper.GetClientContextWithAccessToken(siteUrl.ToString(), token))
 {
 Web currentWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(currentWeb);

 UserCollection webUsers = currentWeb.SiteUsers;
 ctxWorkspace.Load(webUsers);
 ctxWorkspace.ExecuteQuery();
 List<String> usersToAddReadOnlyRights = new List<string>();

 foreach(User user in webUsers)
 {
 if (user.LoginName.ToLowerInvariant().Contains("membership"))
 {
 if (!user.IsSiteAdmin)
 {
 webUsers.RemoveById(user.Id);
 usersToAddReadOnlyRights.Add(user.LoginName);
 }
 }
 }
 currentWeb.Update();
 ctxWorkspace.ExecuteQuery();

 Group visitorGroup = ctxWorkspace.Web.SiteGroups.GetByName(ctxWorkspace.Web.Title + ConfigurationManager.AppSettings["WorkspaceVisitors"]);
 ctxWorkspace.Load(currentWeb);
 ctxWorkspace.Load(visitorGroup);
 ctxWorkspace.Load(webUsers);
 ctxWorkspace.ExecuteQuery();
 foreach (String user in usersToAddReadOnlyRights)
 {
 String[] userLoginNameArray = user.Split('|');
 if(userLoginNameArray != null && userLoginNameArray.Length > 1)
 {
 UserCreationInformation userInfo = new UserCreationInformation();
 userInfo.LoginName = userLoginNameArray[2];
 currentWeb.AddUserToGroup(visitorGroup, userLoginNameArray[2]);

 }
 }
 currentWeb.Update();
 ctxWorkspace.ExecuteQuery();

Remove Workspace users privileges And deny Search Indexing on lists


Uri siteUrl = new Uri(workspaceURL);
 string realm = TokenHelper.GetRealmFromTargetUrl(siteUrl);
 var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, siteUrl.Authority, realm).AccessToken;
 using (var ctxWorkspace = TokenHelper.GetClientContextWithAccessToken(siteUrl.ToString(), token))
 {

 Web currentWeb = ctxWorkspace.Web;
 ctxWorkspace.Load(currentWeb);
 ListCollection lists = ctxWorkspace.Web.Lists;
 ctxWorkspace.Load(lists);
 UserCollection webUsers = currentWeb.SiteUsers;
 ctxWorkspace.Load(webUsers);
 ctxWorkspace.ExecuteQuery();

 foreach (List list in lists)
 {
 list.NoCrawl = true;
 list.Update();
 }

 foreach (User user in webUsers)
 {
 if (user.LoginName.ToLowerInvariant().Contains("membership"))
 {
 if (!user.IsSiteAdmin)
 {
 webUsers.RemoveById(user.Id);
 }
 }
 }
 currentWeb.Update();
 ctxWorkspace.ExecuteQuery();