Convert an existing plain text note field/column to rich text

If you create a SharePoint site column (a note field in this case), associate it with a site content type, and then associate that content type with a list in a sub site, the site column will be available on that library. Obviously right?

However, when you update the site column (and push all changes to lists and libraries) not *all* of the changes you make are in fact pushed down. An example of this is the setting that dictates whether a note field should allow rich text or enforce plain text. If you change this setting at the site column level it will *not* propagate to libraries which already exist. New instances of the column (say if you associated the content type with a list for the first time) will be configured correctly, but existing list-level instances are not updated. NOTE: This is only true for properties specific to particular column type; common properties such as ‘required’ will be pushed down to existing instances of the column at the list level.

Configuring a SharePoint note field to support rich text
Configuring a SharePoint note field

So you want to change a list-level instance of a plain text note column to a rich text note column (or vice-versa, or otherwise change column specific properties or another field type)? You need to do it for every list where the column is in use. That would be very tedious to do via the SharePoint UI, but you can’t anyway. The UI only supports changing the set of common field properties (type, required, hidden, etc).

In comes PowerShell. Below you will find a script which updates a plain text note column to be a rich text note column. It is important to note that this script only updates the list-level columns and not the site column. This means that after running the script, new instances will continue to inherit the site column configuration.

The script takes advantage of recursion using delegate functions which is an approach I blogged about here: PowerShell Recursion with Delegate Functions

Credit also to Chris O’Brien’s topofscript.ps1 for the CSOM integration bit: Using CSOM in PowerShell scripts with Office 365

The script is written for SharePoint Online (and assumes that the SharePoint Online Client Components SDK is installed) but for this to work on-premises you would only need to update the referenced assemblies (v15 for 2013) and modify the code which passes the credentials.

Paul.

Breadcrumb (SiteMapPath) is wrong after moving a site

I have been finding that when moving a site (SPWeb) to a different location in the site hierarchy of a site collection that the breadcrumb would often (not always) be incorrect once the site had been moved.

If you didn’t know, SiteMapProviders are cached in the SharePoint object cache. I’ll put the sporadic nature of the issue down to the natural refresh cycle of the object cache but honestly I’m not completely sure why it doesn’t go wrong all the time. The important bit is that there is way to ensure that the breadcrumb is refreshed correctly every time. For the sake of completeness, here is the SiteMapPath control with its SiteMapProvider property set to CurrentNavSiteMapProviderNoEncode from the custom master page (if you want to read more about this you could start here):

SiteMapPath

If you are suffering this issue I suspect that mentioning the object cache was enough to put you on the right path but I’ll spell it out just in case.

If you run a few lines of code in a WebMoved event receiver (I blogged briefly about attaching these here) you force the object cache to be refreshed whenever a site is relocated. Be warned that if you have a site that leverages the object cache (e.g. use of the cross-list query object, or the content query web part which utilises it) that these operations will need to re-cache and may have some performance impact.

SiteCacheSettingsWriter writer=new SiteCacheSettingsWriter(site);
writer.SetFarmCacheFlushFlag();
writer.Update();

You may need to fetch the SPSite object that is passed into the constructor from within an elevated privileges block to ensure the current user is allowed to perform this action. Obviously that depends on expected audience for this action.

Web Event Receivers: Attach using PowerShell

The following is a simple PowerShell script for attaching SharePoint web event receivers. It is clever enough to check if they have already been attached and hence to avoid duplication.

There are no “gotchas” or anything really worth noting here. This example is pretty much the same as the dozens of list item event receiver examples out there, just targeting a different event receiver type. I am only posting it because I was so surprised that I had to write it myself after failing to find an example to ‘steal’ from the internet – maybe I wasn’t looking hard enough.

The first half of the script is the bit you’ll be interested in (if you are interested in any of it!), the second half is just a usage example.

# Defintion of function to attach web event receivers
# if they are not already added
Function AddWebEventReceivers($webER) 
{   
  $assembly = "*fully_qualified_assembly_name*"
  $class = "*class_name_including_namespace*"

  # Only attach receivers if there aren't already added
  # You can make the check more specific by checking the Type
  # property as well if required
  $existingER = $webER.EventReceivers | Where { $_.Class -eq $class }
  if($existingER -eq $null -or $existingER.length -eq 0)
  {
    $webER.EventReceivers.Add("WebMoved", $assembly, $class)
  }
}

# Iterate all webs and attach the web event receivers to
# sites based on a certain web template
$site = Get-SPSite "*webAppUrl*"
$allWebs = $site.AllWebs
foreach($web in $allWebs)
{
  try 
  {
    # Only act on certain sites
    if($web.WebTemplateId -eq 100009 -and $web.Configuration -eq 2)
    {
      AddWebEventReceivers($web)
    }
  }
  catch [System.Exception]
  {
    $errorMessage = $Error[0]
    Write-Host "Failed: $errorMessage" -NoNewline -F Red
  }
  finally
  {
    $web.Dispose()
  }
}
$site.Dispose()

Modifying content type field properties

A SharePoint site column has a number of properties which, as a developer, you may need to alter. These properties include Name, Type, ShowInEditForm, ShowInDisplayForm, Hidden etc. Some of these properties can be changed once at the site column level and the changes can be propagated to all lists in the site collection. This is surfaced in the UI for a selection of properties:

Using the SharePoint UI to propagate field property changes to all lists
Using the SharePoint UI to propagate field property changes to all lists

The same (with the ability to set many more properties) can be achieved with PowerShell (or, as always, in C#):

The properties that are not listed in the UI may not “update all list columns based on this site column” as you would expect if you are using content types. Content types have a collection of field references (or links) to the list columns which get updated, but the links themselves have their own set of properties which override those set for the list field. This means that if you run the PowerShell snippet above, any existing content types which reference that field will continue to show the field on edit forms. To get around this issue, one must update the content types individually. The PowerShell script below is an example of how you might achieve this.

This is all pretty obvious when you really think about it. It is a necessity to allow for the flexibility of content types on a list to handle list data in their own way.

List view sort order bug

SharePoint was once known for it’s unfortunate list of quirky bugs. As of SharePoint 2010 there are definitely less of these to contend with but some still remain – like this one. The sort order for a list view can get rendered incorrectly when editing the view.

When you define a view programmatically it is up to you to create the XML which defines it. A common view query for a tasks list may be to show all items in descending order so that the newest tasks appear at the top of the list. As such:



SPView view = list.Views["All Tasks"];
view.Query = "<OrderBy><FieldRef Name='ID' Ascending='False' /></OrderBy>";
view.Update();

This will update the view just as you or I would expect. However, there is a significant problem here. When a user modifies this view in the future (via the ViewEdit.aspx) the form will show the view is sorted on ID (correct) but the ‘Show items in ascending order’ radio button will be selected (incorrect). If the user now saves the form, perhaps having added another column, the incorrect sort order will be persisted. To avoid this issue you must capitalise the Ascending attribute value as such:



SPView view = list.Views["All Tasks"];
view.Query = "<OrderBy><FieldRef Name='ID' Ascending='FALSE' /></OrderBy>"
view.Update();

I’m unaware of anywhere within SharePoint that providing upper-case boolean attributes is bad practice so I would recommend always using FALSE instead of False and TRUE instead of True.