SharePoint: Updating file/folder metadata with a # in the name

SharePoint: Updating file/folder metadata with a # in the name

For the longest time this wasn’t an issue. There were just certain characters that weren’t allowed as file or folder names in the Windows world (%&#/\ and so on). Not too long ago, Microsoft decided it’s ok to accept files and folders in SharePoint with either the % or the # in the file or folder name. Great for end users who enjoy that sort of thing…awful for us developers.

For example, in the past I’m sure you did something like this in C# to update a document library folder’s Created date:

using (var ctx = new ClientContext("https://sharepoint.com/sites/sharepointsite"))
{
      var web = ctx.Web;
      ctx.Load(web);
      ctx.ExecuteQuery();
      var folder = web.GetFolderByServerRelativeUrl(web.ServerRelativeUrl+"doclibrary/foldername");
      var item = folder.ListItemAllFields;
      ctx.Load(item);
      ctx.ExecuteQuery();
      item["Created"] = "1/1/2020 12:34";
      item.Update();
      ctx.ExecuteQuery();
}

In the modern SharePoint world this still works, unless the folder has a # in the name somewhere. Since # is considered a URL fragment this presents an internal problem we can’t get to. You can still grab the folder object, but updating it will break with “field or property ListItemAllFields does not exist” or something similar. Thankfully Microsoft added a class to their SharePoint Online CSOM libraries called ResourcePath, that allows you to handle % and # in file and folder names. More details on that here.

Implementation is rather simple. Instead of focusing on the ServerRelativeUrl, we’re going to focus on the ServerRelativePath. First you need to run the FromDecodedUrl on the target server relative URL. Note you will need to ensure there are no HTML Encoded characters in the URL you’re passing in. It’s because we’re assuming this file/folder is not HTML encoded, it’s just using these special characters. So once you have your URL decoded and it just contains the % or # characters as ordinary characters, you can accomplish the same thing as above like so:

using (var ctx = new ClientContext("https://sharepoint.com/sites/sharepointsite"))
{
    var web = ctx.Web;
    ctx.Load(web);
    ctx.ExecuteQuery();
    ResourcePath rpath = ResourcePath.FromDecodedUrl(web.ServerRelativeUrl + "/doclibrary/special#folder");
    var folder = Web.GetFolderByServerRelativePath(rpath);
    var item = folder.ListItemAllFields;
    _context.Load(item);
    _context.ExecuteQuery();
    item["Created"] = "1/1/2020 12:34";
    item.Update();
    folder.ListItemAllFields.Update();
    _context.ExecuteQuery();
}

The extra folder.ListItemAllFields.Update() is probably overkill, but it works! The same principle applies to files:

using (var ctx = new ClientContext("https://sharepoint.com/sites/sharepointsite"))
{
    var web = ctx.Web;
    ctx.Load(web);
    ctx.ExecuteQuery();
    ResourcePath rpath = ResourcePath.FromDecodedUrl(web.ServerRelativeUrl + "/doclibrary/folder/file#name.txt");
    var file = Web.GetFileByServerRelativePath(rpath);
    var item = file.ListItemAllFields;
    _context.Load(item);
    _context.ExecuteQuery();
    item["Created"] = "1/1/2020 12:34";
    item.Update();
    _context.ExecuteQuery();
}

Hope this helps!

Comments are closed.