String in item’s property bag truncated to 255 characters in a document library

Problem

String value in property bag truncated to 255 characters for some documents in a document library.

Case

There are string values saved in the property bag of documents in a document library. The problem of strings truncated to 255 characters is noticed only in some documents. The problem is tested and is present in SharePoint 2010 and SharePoint 2013. For standard lists (not document libraries) the issue is never noticed.

Investigation

After many tests and investigating the traffic with Fiddler the moment when the trunction happens is discovered. The string is truncated by Office. When a document is modified with Office and saved back in the document library all the values in the property bag of that document are truncated to 255 characters. If many key-value pairs contain strings longer than 255 characters they are all truncated to 255 characters. If checking out the documents for editing is required for the document library then the truncation of the properties does not happen immediately when the changes are saved by the user but when the document is checked in. It is tested with Word, Excel and PowerPoint and the results are the same. The properties are not truncated when the document is viewed or checked in/out without modifying the content of the document.

Solution

The limit of 255 characters is forced by Office and I couldn’t fine (and I think there is no way) to increase this limit. The only solution is to redisign and instead of property in the property bag to use a column of type multi line of text with the property SPFieldMultiLineText.UnlimitedLengthInDocumentLibrary set to TRUE.
Then with a PowerShell script or C# code the values can be copied from the property bag item.Propreties[“YourKey”] to the new field item[“fieldName”].

The already truncated values can be brought back by restoring an older version of the item if the versioning is enabled for the document library.

Conclusion

The item’s property bag should be use to save small pieces of information and is not practical to save strings that may grow big over the time. SharePoint allows saving very long strings in the property bag (tested with string with hundred of milions of characters) but that should not be done especialy in document libraries because of the limits of MS Office.

A better place to save strings longer than 255 characters is a column of type multi line of text with the property SPFieldMultiLineText.UnlimitedLengthInDocumentLibrary set to TRUE. The field can be set to hidden if the users should not be able to view or edit the field value.

More tests (extremes)

While I was at it I continued testing by saving very long strings in the property bag and check how Office reactes on that.

I mentioned above that strings longer than 255 characters in the property bag are not affected by Office when opening the document in read only mode but for extreemlly long strings the Office is affected and it can’t open the document.

After saving string with millions of characters in the property bag Office fails to open the document and one of the following error messages will be shown:

The file Doc1.docx cannot be opened because there are problems with the contents

The file Doc1.docx cannot be opened because there are problems with the contents


Microsoft Word has stopped working

Microsoft Word has stopped working

These error messages are very generic and may be shown for hundreds of different reasons.
The errors are shown randomlly and sometimes Office succeeds to open the document. The random nature of these events can probably be explained with the actual state and available resources to Office on the client machine when it tries to open the problematic documents with extremely long string in the property bag.

Effects of temporarily disabling versioning for a SharePoint document library

Suppose we have a document library that has major and minor versioning enabled. We want to know what happens if we disable versioning and re-enable it again, and what is lost/retained from the items versions history.

Case:

There is a document library with major and minor versioning enabled, requires check out for editing document and there are workflows associated with the content types. We’ll observe what happens with the version history when the versioning is disabled and re-enabled. When the versioning is disabled the document library contains number of documents in minor and major versions, with version history, some document are in checked out state and there are document with workflows in process.

Test Results

After re-enabled the versioning the version history of the documents is preserved but any change done while the versioning was disabled has increased the major version of the document (document is published).

Example: Before disabling the versioning for the document library one document is in version 0,2 with version history 0.1, 0.2. After the versioning is disabled the item is modified. After re-enabling the versioning the change done while the versioning was disabled has increased the major version of the document (document published), so the versioning history now is 0.1, 0.2, 1.0 instead of 0.1, 0.2, 0.3 how would have been if the versioning was not disabled when the change has happened.

Every document that was not modified while the versioning was disabled has the full version history back and unaffected from the disable-enable versioning process.

Conclusion

If minor versions are enabled for a document library then temporarily disabling versioning will affect the version history if changes are made while the versioning is disabled. The problem is that every change in that period will publish the document to the next major version.

Running code on SharePoint server using application page

When we need to work with SharePoint object model for maintenance reasons or simple tasks we need a way to execute code on a server machine. Example of such situations are: when we want to check the properties of an item, list or web that are not accessible using the UI, or looping through all the items in a list to set a particular field to a specific value etc.
In such cases there are different options to work with SharePoint object model on a server machine where there is no Visual Studio installed:

  1. PowerShell script
  2. Windows application. For example console or WinForms application developed on Development environment by referencing Microsoft.SharePoint.dll
  3. Application page with inline code

This post is a quick how-to guide on using application page to run inline C# code on a server.
This post is not a guide how to develop application pages for a SharePoint solution. In that case you would write the code in the page’s code behind and pack everything in a solution package.

Step 1

Create a file with extension .aspx (in this guide we will name it appPage1.aspx)

Step 2

Copy and paste the following content to appPage1.aspx based on the SharePoint version you need the page for.

For Microsoft Office SharePoint Server 2007 (MOSS 2007):

<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71E9BCE111E9429C" %>
<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Utilities" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormSection" Src="~/_controltemplates/InputFormSection.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="InputFormControl" Src="~/_controltemplates/InputFormControl.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ButtonSection" Src="~/_controltemplates/ButtonSection.ascx" %>
<%@ Register TagPrefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <%
            try
            {
                SPWeb web = SPContext.Current.Web;
		        Response.Write(web.Title);
                //your code here
            }                
            catch (Exception ex)
            {
                Response.Write("<br/><br/>" + ex.ToString());
            }

        %>
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
</asp:Content>

For SharePoint 2010:

<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="asp" Namespace="System.Web.UI" Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Page Language="C#" AutoEventWireup="true" DynamicMasterPageFile="~masterurl/default.master" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase" %>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <%
            try
            {
                SPWeb web = SPContext.Current.Web;
		        Response.Write(web.Title);
                //your code here
            }                
            catch (Exception ex)
            {
                Response.Write("<br/><br/>" + ex.ToString());
            }

        %>
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
</asp:Content>

For SharePoint 2013

<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%> 
<%@ Page Language="C#" MasterPageFile="minimal.master"  %> 
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %> 
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Import Namespace="Microsoft.SharePoint" %> 
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="wssawc" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> 
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="wssuc" TagName="LinkSection" src="~/_controltemplates/15/LinkSection.ascx" %>

<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
        <%
            try
           {
                SPWeb web = SPContext.Current.Web;
		        Response.Write(web.Title);
                //your code here
            }              
            catch (Exception ex)
            {
                Response.Write("<br/><br/>" + ex.ToString());
            }

        %>
</asp:Content>

<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server" >
</asp:Content>

Step 3

Write your code in the space specified with “//your code here” in the aspx page.
If you need you can reference your assemblies in the page. The referenced assemblies must be available on the server where this page will be used.

Step 4

Copy the file to the LAYOUTS folder in SharePoint root directory.
The path to the layouts folder is:

For MOSS 2007:

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Template\Layouts

For SharePoint 2010

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Template\Layouts

For SharePoint 2013

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\15\Template\Layouts

Step 5

Open the browser and navigate to appPage1.aspx.
The Url is:

For MOSS 2007 and SharePoint 2010:

yourSiteUrl/_layouts/appPage1.aspx

For SharePoint 2013:

yourSiteUrl/_layouts/15/appPage1.aspx

The code will run in the context of the web where you open the page and in the context of the logged in user. You can elevate the privilages of the logged in user with SPSecurity.RunWithElevatedPrivilages and instantiate new SPSite to run the code in the context of system account.

Modifying a sealed choice field using PowerShell

To modify a sealed field it must be first “unsealed” by setting Sealed property to False. This can be done using PowerShell.

For demonstration purposes let’s say we have a list List1 which contains a sealed choice field ChoiceField1 with three choices Choice #1, Choice #2, Choice #3, and the default choice is Choice #1.

Unseal the field

Below is the script to first “unsealed” the field

	Add-PSSnapin Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue
	$web = Get-SPWeb -Identity "http://weburl"
	$list = $web.GetList($web.Url + "/Lists/List1")
	$field = $list.Fields.GetField("ChoiceField1")
	$field.Sealed = $false
	$field.Update()

Change the choices order

To change the choices order from Choice #1, Choice #2, Choice #3 to Choice #2, Choice #3, Choice #1 run the script below

	$web = Get-SPWeb -Identity "http://weburl"
	$list = $web.GetList($web.Url + "/Lists/List1")
	$field = $list.Fields.GetField("ChoiceField1")
	$field.Choices.Remove("Choice #1");
	$field.Choices.Remove("Choice #2");
	$field.Choices.Remove("Choice #3");
	$field.Choices.Add("Choice #2")
	$field.Choices.Add("Choice #3")
	$field.Choices.Add("Choice #1")
	$field.Update()

Change the default choice

To change the default choice from Choice #1 to Choice #3 run the script below

	$web = Get-SPWeb -Identity "http://weburl"
	$list = $web.GetList($web.Url + "/Lists/List1")
	$field = $list.Fields.GetField("ChoiceField1")
	$field.DefaultValue = "Choice #3"
	$field.Update()

Seal the field back

	$web = Get-SPWeb -Identity "http://weburl"
	$list = $web.GetList($web.Url + "/Lists/List1")
	$field = $list.Fields.GetField("ChoiceField1")
	$field.Sealed = $true
	$field.update()
	$web.Dispose()

For every script above I used new $web so every script is ready for use. You can get one $web and combine pieces of the above scripts.

Content Approval implementation options in SharePoint

There are different options to implement item approval functionality for SharePoint list items. Below are listed some option starting from the simplest, out-of-the-box features to workflows developed in Visual Studio.

1. Set ‘Require content approval’ in list’s Versioning settings.

This is the simplest way to have content approval functionality in SharePoint and it doesn’t require workflow.
To enable Content Approval go to list’s Settings -> Versioning settings and set ‘Require content approval for submitted items?’ to Yes.
Enable versioning as per your requirements.
Workflow Settings

2. Approval Workflow.

This is achieved by using out-of-the-box workflow ‘Approval – SharePoint 2010’ workflow and involves task generation and options to Approve/Reject/Request changes/Reassign tasks)
To use this workflow follow the steps below:
1. Make sure the site collection feature ‘Workflows’ is activated
2. Go to List Settings -> Workflow Settings and click ‘Add’ to add new workflow. Choose Approval – SharePoint 2010, specify Name, choose Task List, History List and specify the Start Options.
Require Content Approval screen
Click Next and specify the other settings (Approvers, task duration, enable content approval etc.)
After adding the workflow it will be available for the list items and it will start automatically or can be started manually depending on the workflow settings.

3. Create custom workflow using SharePoint Designer

With SharePoint Designer can be created custom workflows with a relatively easy way and without coding. SharePoint Designer has improved noticeably with every major version and there is a lot of flexibility and has a quite long list of actions to use when creating workflows for different business processes including content approval processes.

4. Creating workflows using Visual Studio

This is the most advanced way of creating custom workflows. It has full flexibility to implement any functionality and has the advantage of building workflows for easy deployment in different environments.

Conclusion

There is no strict rule when to use which option. Its best to evaluate every option starting from the easiest one (option 1) until the most appropriate option is chosen considering the requirements and the available resources (time and people)

Site collection backup/restore vs. site export/import with focus on running workflows, version history and auditing

Custom SharePoint solutions usually contain custom lists with custom event receivers, custom workflows, maintain version history, use auditing etc. For a site with lists that have those customization it’s important to make sure that the backup/restore process will not lose any of the running workflows, workflow tasks and their status, items version history (major and minor versions), registered audit events etc.

Regarding audit events, in fact they are saved in Audit table in the content database and site backup/restore or export/import will not affect that table but can make other changes(for example new site GUID) which will result in invalid rows in that table (one of the columns is Site ID (GUID)).

Database attach is always the best way to avoid any problems of this kind but in some cases for various reasons very frequent backup of the content database is not preferred and backup of a single site collection (SPSite) or single site (SPWeb) is required. Another reason for testing site export/import is that I’ve seen administrators using export/import for migration to another location and as a more frequently running backup plan and I was asked is it safe to do that for custom solution.

Test case

I tested site collection backup/restore and site export/import in SharePoint 2010. In the site there was a document library with versioning (major and minor) enabled, auditing was enabled and there were custom workflows associated with the list. In the time of back up there were documents in minor and major version. Also some of the documents had workflows in running state. After the backup some versions from items versions history were deleted, running workflows were completed and workflows on other items were started. Also some of the documents were deleted and new documents created. After that the restore/import was performed and the restored/imported site was compared with the original state (state when the site was backed up/exported). Import of the exported site was tested by importing on the same location and also importing on another sub site.

Below are the commands for backup/restore and export/import and the results after restore/import. The focus is on running workflows, version history and registered auditing events.

Site collection backup

PowerShell command to backup a site collection

        Backup-SPSite -Identity "site collection url" -Path "backup file path"

More information for Backup-SPSite: http://technet.microsoft.com/en-us/library/ff607901.aspx

Site collection restore

PowerShell command to restore a site collection

	Restore-SPSite -Identity "site collection url" -Path "backup file path"

More information for Restore-SPSite: http://technet.microsoft.com/en-us/library/ff607788.aspx

Restore results:

The results are the same when restoring on the same location or another location, in the same web application or another web application.

Results:

  • The restored site collection has new site ID (GUID).
  • All items versions are restored successfully with the original correct datetime value for every version.
  • All items workflows are restored successfully
  • Audit events are lost. This happens because of the new site ID (GUID). This can be fixed by updating Audit table in the content database. If the site collection is restored in the same location or another location that uses the same content database then rows in Audit table should be updated by writing the new Site ID in the rows that have the old Site ID. If the restore is done on another location that uses another content database then new rows must be created in the Audit table in the new content database by reading the old audit events from the Audit table in the old content database.

Site Export

PowerShell command to export SPWeb:

	Export-SPWeb [-Identity] "site url or GUID" -Path "backup file path"

More information for Export-SPWeb: http://technet.microsoft.com/en-us/library/ff607895.aspx
Important: Export-SPWeb does not export the running workflows.

Site import

Powershell command to import SPWeb:

	Import-SPWeb [-Identity] "site url or GUID" -Path "backup file path"

More information for Import-SPWeb: http://technet.microsoft.com/en-us/library/ff607613.aspx

Import in the same location

If there are event receivers running custom code in the lists it’s recommended to remove all of them before import to avoid any failure caused by the event receiver logic. Depending on the logic of the event receivers import may completely fail or the imported web may have wrong items version history and other problems. After import event receivers can be added back. For removing/adding event receivers with PowerShell check one of my older posts Add, Modify or Delete List Event Receivers with PowerShell

Import results:

  • Import operation does not import the workflows (as expected, because they don’t get exported with Export-SPWeb).
  • Import does not affect the currently running workflows but import of the document versions fails for those documents with running workflow.
  • Versions are imported only for document with no workflows in running state when importing.
  • Versions date and time are lost. All versions have datetime value of the time when the import has been performed.
  • Audit events are not affected by the import, so all events are retained including those registered between export and import

Import in another sub site

The following must be done before importing the exported site:

  • Create new site using the same template and same language as the exported site
  • As explained above, removing event receiver is strongly recommended

Import results:

  • All running workflows are lost
  • All custom site properties and custom item properties are lost (properties in SPWeb.Properties and SPItem.Properties hashtables)
  • All workflow associations are lost
  • Document versions are imported but date and time for the versions are lost. All versions have datetime value of the time when the import has been performed.
  • Audit events are lost
  • Workflow tasks are lost

Conclusion:

Database attach of a backed up content database is superior for custom SharePoint solutions that contain custom workflows, custom web and item properties, custom event receivers, version history etc. To avoid big content database and long backup times its better the custom solutions to be installed in a site collection that has its own content database instead of sharing one content database with other site collections. That way backup/restore space and time will stay in normal and manageable boundaries. In that case you can stick to database backup as the best backup/restore plan for highly customized and big SharePoint solution.

Site collection backup/restore is better than SPWeb export/import but not as trouble free as database backup/restore plan. The problems are caused by the new Site ID (GUID) generated. That causes lose of audit events, or more precisely additional work to correct the Audit table after the restore.

Site export/import is almost useless for custom solutions that contain custom workflows, event receivers, custom web and item properties, custom event receivers, version history etc. It has problems even if it’s used for simple sites that use only SharePoint out of the box functionality if it has lists with workflows and versioning enabled.

‘Edit Document’ button instead of ‘Check Out’ when opening a Word document

Error:

“A problem occurred while connection to the server. If the problem continues, contact your administrator.” when trying to edit a Word document opened in read only mode in SharePoint 2010. The only way to edit a document now is to first Check Out the document in SharePoint then open the document for editing in MS Word.

The problematic library was created using Visual Studio 2010 wizard for creating a list instance in a SharePoint project.

Problem:

When a document that is not checked out is opened in MS Word ‘Edit Document’ button is shown (Screenshot 1.) instead of ‘Check Out’ button (Screenshot 2).

This document was opened from a server in read-only mode. Edit Doucment

This document was opened from a server in read-only mode. Edit Document

Screenshot 1.

To modify this server document, you must check it out. Check Out

To modify this server document, you must check it out. Check Out

Screenshot 2.

After clicking ‘Edit Document’ the following error is shown (Screenshot 3):

A problem occurred while connection to the server. If the problem continues, contact your administrator.

A problem occurred while connection to the server. If the problem continues, contact your administrator.

Screenshot 3.

Non of the solutions for similar problems I found online solved my problem. had to check the schema of the library and investigate with Fiddler.

After comparing the schema of a list created with the UI (this library works fine) and a the schema of the document library created with Visual Studio 2010 (this library has the problem) I noticed that the library created with the UI has no “/Lists/” part in the URL while the library created with Visual Studio has the “/List” part in the URL.

It turned out that Microsoft Word is trying to access the library by using URL composed as webUrl + Library

So to avoid this problem when creating document libraries with VS the part “/Lists/” should be removed from the URL.

Screenshot 4.

Relative Url for deployment

Relative Url for deployment

Since that time I always double check the URLs of lists and libraries when created with Visual Studio.

Good Url for document libraries: webUrl/DocumentLibrary1

Bad Url for document libraries: webUrl/Lists/DocumentLibrary1

For standard lists it doesn’t matter the “/Lists” part in the URL. Anyhow, for standard list (not document libraries) I prefer to include “/Lists” in the URL.

If creating a new library without /Lists part in the Url is not an option for you then another solution would be to change the URL of the existing library. I didn’t have to do that in my situation because there were not that much documents in the problematic library.
Changing just the URL of an existing library without recreating it deserves a separate post because there may be other issues to consider in that case.
In both cases one of the problems I can think of is if there are a lot of documents already in the library and in their content they reference other documents in the library. Changing the URL of the library will break those links so all the old hyperlinks in the documents content must be corrected manually or programmatically.

URL of an existing library can be changed with PowerShell, Windows Explorer or SharePoint Designer. For more details how to change the URL of an existing list check my other post
Change the URL of a SharePoint list or library

Update:

I tested by changing the URL of the same document library and the problem I expected with broken links in the documents content is not present. The hyperlinks are corrected automatically.
I investigated one document just after fixing the URL and before opening it in Word. I checked in \word\_rels\document.xml.rels and the hyperlinks were already corrected and were using the new URL of the document library without the “/Lists” part.
In \word\_rels\settings.xml.rels I noticed a Relationship element with Type=…./attachedTemplete with Target set to the document library’s document template using the old URL but that didn’t cause any problem and got fixed automatically with the first opening of the document in Word.

So far I haven’t notice any issue after changing the URL of the problematic library so creating another library with good URL is not necessary. Correcting the URL of the same library works fine and solves the problem.

Getting document by file name with PowerShell using CAML

Getting one document from a document library by specifying the document’s name is possible by using CAML. With this method the looping through all the documents is avoided.

Here is a sample script to get the document with name ‘Doc1.docx’ from a document library:

$web = Get-SPWeb -Identity http://weburl
$list = $web.Lists["ListName"];
$query = New-Object Microsoft.SharePoint.SPQuery
$caml ='<Where><Eq><FieldRef Name="FileLeafRef"/><Value Type="File">Doc1.docx</Value></Eq></Where>'
$query.Query = $caml
$query.RowLimit = 1
$items = $list.GetItems($query)
$item = $items[0]

RENDER FAILED when filtering by a column in a grouped view

Error:

<!–# RENDER FAILED –>

RENDER FAILED is one of those problems that can happen in different situations which have very little in common with each other.
It may also be present, then fixed with one cumulative update and come back with the next cumulative update.

Case:

In a document library in SharePoint 2010 when filtering by a column that has more than 500 different values instead of listing all the choices in the dropdown it shows the link “Show filter choices”. When clicking this link the page reloads and shows dropdown controls without styling which contain all the choices no matter how many they are. This is the normal behavior and it should work for every view no matter is it grouped or not, one or two level grouping.

In my case when clicking “Show filter choices” in a grouped view of a document library an empty page with <!–# RENDER FAILED –> on the left top corner is shown.

Render Failed screenshot

Investigation:

I found online that other users have complained for <!–# RENDER FAILED-> error and they have reported it to Microsoft. There are  some hotfixes that Microsoft has released but none of the cases reported by users were the same as my case. Anyhow I installed the latest cumulative update but the problem was still there.

I created another document library using UI, generated more than 500 items,created new view, set up the grouping and surprisingly “Show filter choices” was working fine and it was not giving any error.

After inspecting the page of the problematic view I found out that it was using ListViewWebPart webpart. That webpart is the default webpart for list views in MOSS 2007. In SharePoint 2010 the default list view webpart is XsltListViewWebPart. That explains why the view in the new list was working fine.

It turned out that the site collection where the problem was occurring has been migrated from MOSS 2007 to SharePoint 2010 by attaching the content database. That explains why those old views were using ListViewWebPart.

To fix the problem I had to replace ListViewWebPart webparts with XsltListViewWebPart  webparts. I didn’t have to do that manually.. Fortunately just entering in edit mode and clicking Apply/OK for every old web part SharePoint automatically changes ListViewWebPart to XsltListViewWebPart. After that filtering by a column with more than 500 choices was working in the old grouped views too.

Solution:

Do the following for all the views that have the problem:

  1. Open view’s page in edit mode.
  2. Open view’s webpart in edit mode.
  3. Without changing anything click Apply/OK. That will automatically change the old ListViewWebPart to the new XsltListViewWebPart.
  4. If the problem is still present check the view’s page to make sure that the control is changed from ListViewWebPart to XsltListViewWebPart. This can be checked by adding ?contents=1 to the view’s Url or by opening the page in SharePoint Designer

This solution has fixed the problem for lists and document libraries in site collections that have been migrated from MOSS 2007 to SharePoint 2010. The same problem is seen and solved with this solution in lists and document libraries in SharePoint 2010 created by custom solutions developed originally for MOSS 2007,migrated to work for SharePoint 2010 and installed in SharePoint 2010.

Hide ‘Recently Modified’ from Quick Launch

When opening Wiki pages in the quick launch ‘Recently Modified’ is shown with links to the recently modified pages.
Below are three different ways to hide ‘Recently Modified’ from quick launch

1. With Content Editor Web Part.

Add a Content Editor web part in the page and add the following CSS:

<style> .s4-recentchanges{ DISPLAY:none; } </style>
Pros:

No need to modify the master page or anything in the SharePoint root folder

Cons:

‘Recently Modified’ is hidden only when visiting the pages that contain the content editor webpart with the CSS. So this method requires manual work to add the webpart in every new page created.

2. Modify the master page.

  1. Create new master page (by copying the default master page)
  2. Set DISPLAY: none for .s4-recentchanges in the master mage
  3. Set the new master page to be the default master page.
Pros:

One time job, so no need to hide from every new page.

Cons:

‘Recently Modified’ will be hidden from every page in the site, not just wiki pages.

3. Modify wkpstd.aspx file in SharePoint root directory

  1. Open the following the file wkpstd.spx located in the SharePoint root directory ..14/TEMPLATE/document templates/wkpstd.aspx
  2. In ‘RecentChangesMenu’ control add visible=”false”.

    <SharePoint:RecentChangesMenu runat="server" id="RecentChanges" visible="false"/>
    
  3. Save the file
Pros:

Will hide ‘Recently Modified’from all wiki pages in the farm and will not affect other pages

Cons:

Modifying files in SharePoint root manually is NOT RECOMANDED. This option is listed here just to show that its possible to do it this way but you should consider option 1 and 2 first.

Hide or change quick launch’s width with CSS

Hide quick launch

To hide the quick launch the following CSS can be used:

	<style type="text/css">
	.s4-ca {
	 margin-left: 0px;
	}
	#s4-leftpanel {
	 display: none;
	}
	</style>

Change quick launch’s width

Quick launch’s width can be changed with the following CSS:

	<style type="text/css">
	.s4-ca {
	margin-left: 200px;
	}
	body #s4-leftpanel {
				   width: 200px;
	float:left;
	}
	</style>

The CSS can be added to a content editor web part to apply the change to a particular page or can be added to the master page to apply it for the whole site.

Another way to apply it to one site it to create a css file (let’s name it MyCss.css) and paste the css code above. Then upload the file to the site’s style library. Then set the site’s AlternateCssUrl property to the uploaded css file. That can be done using the following PowerShell script:

	Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
	$web=get-spweb http://weburl
	$site.AlternateCssUrl="http://sitecollectionurl/Style%20Library/MyCss.css"
	$web.Update();

Add, Modify or Delete List Event Receivers with PowerShell

Developing and troubleshooting custom SharePoint solutions always involves checking, adding, modifying or deleting event receivers. When working on production servers usually we don’t have all the tools that we have in our own VMs. In those cases we can use PowerShell or write inline code in an application page and put it in the LAYOUTS folder in SharePoint Root.

Below are some PowerShell commands to check, add, modify and remove list event receivers.

It goes without saying that you should be very careful when working with event receivers as with everything else in SharePoint. Save the original state with a back up, or at least make sure you know which event receivers are there with all their properties before modifying anything. That way you can get everything back in the original state.

Checking event receivers:

After getting the list in PowerShell you can just run $list.EventReceivers and it will show all the event receivers will all their properties.

Add-PSSnapin Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue

$web = Get-SPWeb -Identity http://....
$list = $web.GetList($web.Url + '/Lists/' + “list name”)
$list.EventReceivers

To save the result in a text file for future reference execute the following command:

$list.EventReceivers | Out-File -filepath "D:\EventReceivers.txt"

Add EventReceiver

To add an event receiver you need to know the full assembly name (you can get that from GAC) and the class name that contains the event receivers

Add-PSSnapin Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue

$web = Get-SPWeb -Identity http://....
$list = $web.GetList($web.Url + "/Lists/" + “list name”)

$type = "ItemAdding" #or any other type, like ItemDeleting, ItemAdded, ItemUpdating ...
$assembly = "YourAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5eff...(here goes assebly's token"
$class = "Your Class"

$list.EventReceivers.Add($type, $assembly, $class)

$web.Dispose()

Modify Event Receiver

For example, to change an after event EventReceiver from asynchronous to synchronous

Add-PSSnapin Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue

$web = Get-SPWeb -Identity http://...
$list = $web.GetList($web.Url + "/Lists/" + “list name”)

$type = "ItemAdded" #or any other type, like ItemDeleting, ItemAdding, ItemUpdating, ...

$numberOfEventReceivers = $list.EventReceivers.Count

if ($numberOfEventReceivers -gt 0)
{
 for( $index = $numberOfEventReceivers -1; $index -gt -1; $index–-)
 {
 	$receiver = $list.EventReceivers[$index] ;
 	$name = $receiver.Name
 	$typ = $receiver.Type ;

 if ($typ -eq $type)  #or you can check ($name -eq "event receiver's name") if you have more then one event receivers of the same type
 {
 	$receiver.Synchronization = "Synchronous"
	$receiver.Update()
	Write-Host "Event receiver " $name " is changed to Synchronous"
 }
 }
}
else
{
 	Write-Host " There is no EventReceiver of type " $type " registered for this list "
}

$web.Dispose()

Delete Event Receivers

Run the following to delete a specific event receiver (in this example ItemDeleting event receiver)

Add-PSSnapin Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue

$web = Get-SPWeb -Identity http://...
$list = $web.GetList($web.Url + "/Lists/" + “list name”)

$type = "ItemDeleting" #or any other type, like ItemDeleting, ItemAdding, ItemUpdating, ...

$numberOfEventReceivers = $list.EventReceivers.Count

if ($numberOfEventReceivers -gt 0)
{
   for( $index = $numberOfEventReceivers -1; $index -gt -1; $index–-)
   {
      $receiver = $list.EventReceivers[$index] ;
      $name = $receiver.Name
      $typ = $receiver.Type ;

      if ($typ -eq $type)  #or you can check ($name -eq "event receiver's name") if you have more then one event receivers of the same type
      {
         $receiver.Delete()
         Write-Host "Event receiver " $name " is deleted"
      }
   }
}
else
{
   Write-Host " There is no EventReceivers of type " $type " registered for this list "
}

$web.Dispose()

Set permissions on SharePoint list and items programmatically

This is a short guide on how to set permissions on a SharePoint list/item using server-side object model.

  1. Get the principal object (SPPrincipal) to which you want to grant permission to. It by sharepoint user or group.
  2. Get the list
    SPList list = web.GetListFromUrl(web.Url + “/Lists/ListName/Forms/AllItems.aspx“);
    
  3. Break role inheritance for the list
    list.BreakRoleInheritance(false);
    

    or pass ‘true’ if you want to copy the current role assignments when breaking the role inheritance.

  4. Create new instance of SPRoleAssignment
    SPRoleAssignment roleAssignment = new SPRoleAssignment(principal);
    
  5. Create new instance of SPRoleDefinition
    SPRoleDefinition roleDefinition = new SPRoleDefinition();
    
  6. Set the SPRoleType you want to the role definition.
    Example for read permissions:

    	roleDefinition = web.RoleDefinitions.GetByType(SPRoleType.Reader);
    
  7. Create new instance of SPRoleDefinitionBindingsCollection and add the role definition created above
    SPRoleDefinitionBindingCollection roleDefinitionBindingCollection = new SPRoleDefinitionBindingCollection();
    
  8. Import the role definition binding collection to the role assignment
    roleAssignment.ImportRoleDefinitionBindings(roleDefinitionBindingCollection);
    
  9. Add the role assignment to the list’s role assignments collection
        list.RoleAssignments.Add(roleAssignment);
    

Here is the complete code for setting read permissions for a principal:

SPRoleAssignment roleAssignment = new SPRoleAssignment(principal);
SPRoleDefinition roleDefinition = new SPRoleDefinition();
roleDefinition = web.RoleDefinitions.GetByType(SPRoleType.Reader);
SPRoleDefinitionBindingCollection roleDefinitionBindingCollection = new SPRoleDefinitionBindingCollection();
roleDefinitionBindingCollection.Add(roleDefinition);
roleAssignment.ImportRoleDefinitionBindings(roleDefinitionBindingCollection);
web.AllowUnsafeUpdates = true;
list.RoleAssignments.Add(roleAssignment);
web.AllowUnsafeUpdates = false;

The same logic is valid for setting item’s permissions by just replacing SPList with SPListItem in the code:

SPRoleAssignment roleAssignment = new SPRoleAssignment(principal);
SPRoleDefinition roleDefinition = new SPRoleDefinition();
roleDefinition = web.RoleDefinitions.GetByType(SPRoleType.Reader);
SPRoleDefinitionBindingCollection roleDefinitionBindingCollection = new SPRoleDefinitionBindingCollection();
roleDefinitionBindingCollection.Add(roleDefinition);
roleAssignment.ImportRoleDefinitionBindings(roleDefinitionBindingCollection);
web.AllowUnsafeUpdates = true;
item.RoleAssignments.Add(roleAssignment);
web.AllowUnsafeUpdates = false;

SharePoint user deleted from Active Directory

When a SharePoint user is deleted for Active Directory it is not deleted from SharePoint automaticlly. If there is User Profiles service configured for the farm then the user will be deleted from the User Profiles with the next users profiles syncornization job but will still remail in the site collections. To remove the user from a site collection it must be removed manually by deleting it from site collection’s users list located on the following Url /_catalogs/users/detail.aspx

%d bloggers like this: