Moving a SharePoint folder and contents to differe

2019-03-29 13:15发布

问题:

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!

回答1:

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();
}


回答2:

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()