Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving a SharePoint folder and contents to different location in same Document Library

I'm looking for a way to move a folder and all it's contents to a different location in the same library using the Client Object Model for SharePoint 2010 (C#).

For example we have a folder for a project (say 12345) and it's URL is

http://sharepoint/site/library/2012/12345

where 2012 represents a year. I'd like to programmatically move the 12345 folder to a different year, say 2014 which probably exists already but may not.

I've searched around but the solutions I'm getting seem extremely complicated and relevant to moving folders to different site collections, I'm hoping because it's in the same library there might be a simpler solution? One idea I have is to rely on Explorer View instead of CSOM?

Thanks a lot!

like image 523
ebooyens Avatar asked Oct 11 '14 18:10

ebooyens


2 Answers

There is no built-in method in SharePoint CSOM API for moving Folder with Files from one location into another.

The following class represents how to move files from source folder into destination folder:

public static class FolderExtensions
{


    public static void MoveFilesTo(this Folder folder, string folderUrl)
    {
        var ctx = (ClientContext)folder.Context;
        if (!ctx.Web.IsPropertyAvailable("ServerRelativeUrl"))
        {
            ctx.Load(ctx.Web, w => w.ServerRelativeUrl);   
        }
        ctx.Load(folder, f => f.Files, f => f.ServerRelativeUrl, f => f.Folders);
        ctx.ExecuteQuery();

        //Ensure target folder exists
        EnsureFolder(ctx.Web.RootFolder, folderUrl.Replace(ctx.Web.ServerRelativeUrl, string.Empty));
        foreach (var file in folder.Files)
        {
            var targetFileUrl = file.ServerRelativeUrl.Replace(folder.ServerRelativeUrl, folderUrl);
            file.MoveTo(targetFileUrl, MoveOperations.Overwrite);
        }
        ctx.ExecuteQuery();

        foreach (var subFolder in folder.Folders)
        {
            var targetFolderUrl = subFolder.ServerRelativeUrl.Replace(folder.ServerRelativeUrl,folderUrl);
            subFolder.MoveFilesTo(targetFolderUrl);
        }
    }


    public static Folder EnsureFolder(Folder parentFolder, string folderUrl)
    {
        var ctx = parentFolder.Context;
        var folderNames = folderUrl.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
        var folderName = folderNames[0];
        var folder = parentFolder.Folders.Add(folderName);
        ctx.Load(folder);
        ctx.ExecuteQuery();

        if (folderNames.Length > 1)
        {
            var subFolderUrl = string.Join("/", folderNames, 1, folderNames.Length - 1);
            return EnsureFolder(folder, subFolderUrl);
        }
        return folder;
    }
}

Key points:

  • allows to ensure whether destination folder(s) exists
  • In case of nested folders, its structure is preserved while moving files

Usage

var srcFolderUrl = "/news/pages";
var destFolderUrl = "/news/archive/pages";
using (var ctx = new ClientContext(url))
{      
    var sourceFolder = ctx.Web.GetFolderByServerRelativeUrl(srcFolderUrl);
    sourceFolder.MoveFilesTo(destFolderUrl);
    sourceFolder.DeleteObject(); // delete source folder if nessesary
    ctx.ExecuteQuery();
}
like image 193
Vadim Gremyachev Avatar answered Sep 23 '22 19:09

Vadim Gremyachev


Just in case someone needs this translated to PnP PowerShell. It's not battle tested but works for me. Versions and metadata moved as well within the same library.

$list = Get-PnPList -Identity Documents
$web = $list.ParentWeb
$folder = Ensure-PnPFolder -Web $list.ParentWeb -SiteRelativePath "Shared Documents/MoveTo"
$tofolder = Ensure-PnPFolder -Web $list.ParentWeb -SiteRelativePath "Shared Documents/MoveTwo"

function MoveFolder
{
    [cmdletbinding()]
    Param (
        $web,
        $fromFolder,
        $toFolder
    )
    $fromFolder.Context.Load($fromFolder.Files)
    $fromFolder.Context.Load($fromFolder.Folders)
    $fromFolder.Context.ExecuteQuery()
    foreach ($file in $fromFolder.Files)
    {
        $targetFileUrl = $file.ServerRelativeUrl.Replace($fromFolder.ServerRelativeUrl, $toFolder.ServerRelativeUrl);
        $file.MoveTo($targetFileUrl, [Microsoft.SharePoint.Client.MoveOperations]::Overwrite);
    }
    $fromFolder.Context.ExecuteQuery();

    foreach ($subFolder in $fromFolder.Folders)
    {
        $targetFolderUrl = $subFolder.ServerRelativeUrl.Replace($fromFolder.ServerRelativeUrl, $toFolder.ServerRelativeUrl);
        $targetFolderRelativePath = $targetFolderUrl.SubString($web.RootFolder.ServerRelativeUrl.Length)
        $tofolder = Ensure-PnPFolder -Web $list.ParentWeb -SiteRelativePath $targetFolderRelativePath
        MoveFolder -Web $web -fromFolder $subFolder -toFolder $tofolder
    }
}

$web.Context.Load($web.RootFolder)
$web.Context.ExecuteQuery()
MoveFolder -Web $web -fromFolder $folder -toFolder $tofolder
$folder.DeleteObject()
$web.Context.ExecuteQuery()
like image 35
Guðjón Örn Þorsteinsson Avatar answered Sep 23 '22 19:09

Guðjón Örn Þorsteinsson