locked
Move a file across site collections with version history RRS feed

  • Question

  • I have the need to move a document using Client Object Model across site collections in SharePoint Online while retaining its metadata and version history.

    The sp.movecopyutil methods allows us to move files within a site collection while retaining the item metadata, moderation status, and version history. However the sp.movecopyutil does not work properly when we try to move a document across site collections (Moderation status and version history are not retained).

    Is there any other API or methods available to move documents across site collection while retaining the metadata, moderation status, and with version history?

    If there is no standard API available for this, what would be the best way to go about achieving this move action?


    Suresh Kumar Senapati

    Thursday, December 3, 2015 3:08 PM

Answers

  • Hi,

    Here is a blog for your reference:

    Copy a file across site collections with CSOM and REST

    http://sanderlesage.blogspot.jp/2014/07/copy-file-cross-site-collection-csom-rest.html

    Or the following code snippet for your reference:

    public static void CopyDocuments()
    {
    	var login = "<user@tenant>.onmicrosoft.com";
    	var password = "<password>";
    	string srcUrl="https://xxx.sharepoint.com/sites/site1";
    	string destUrl="https://xxx.sharepoint.com/sites/site2";
    	string srcLibrary="library1"; 
    	string destLibrary="library1";
    	
    	var securePassword = new SecureString();
    	foreach (char c in password)
    	{
    		securePassword.AppendChar(c);
    	}
    
    	var onlineCredentials = new SharePointOnlineCredentials(login, securePassword);
    
    	// set up the src client
    	SP.ClientContext srcContext = new SP.ClientContext(srcUrl);
    	srcContext.Credentials = onlineCredentials;
    
    	// set up the destination context (in your case there is no needs to create a new context, because it would be the same library!!!!)
    	SP.ClientContext destContext = new SP.ClientContext(destUrl);
    	destContext.Credentials = onlineCredentials;
    
    
    	// get the list and items
    	SP.Web srcWeb = srcContext.Web;
    	SP.List srcList = srcWeb.Lists.GetByTitle(srcLibrary);
    	SP.ListItemCollection col = srcList.GetItems(new SP.CamlQuery());
    	srcContext.Load(col);
    	srcContext.ExecuteQuery();
    
    	// get the new list
    	SP.Web destWeb = destContext.Web;
    	destContext.Load(destWeb);
    	destContext.ExecuteQuery();
    
    	foreach (var doc in col)
    	{
    		try
    		{
    			if (doc.FileSystemObjectType == SP.FileSystemObjectType.File)
    			{
    				// get the file
    				SP.File f = doc.File;
    				srcContext.Load(f);
    				srcContext.ExecuteQuery();
    
    				// build new location url
    				string nLocation = destWeb.ServerRelativeUrl.TrimEnd('/') + "/" + destLibrary.Replace(" ", "") + "/" + f.Name;
    
    				// read the file, copy the content to new file at new location
    				SP.FileInformation fileInfo = SP.File.OpenBinaryDirect(srcContext, f.ServerRelativeUrl);
    				SP.File.SaveBinaryDirect(destContext, nLocation, fileInfo.Stream, true);
    			} 
    
    			if (doc.FileSystemObjectType == SP.FileSystemObjectType.Folder)
    			{
    				// load the folder
    				srcContext.Load(doc);
    				srcContext.ExecuteQuery();
    
    				// get the folder data, get the file collection in the folder
    				SP.Folder folder = srcWeb.GetFolderByServerRelativeUrl(doc.FieldValues["FileRef"].ToString());
    				SP.FileCollection fileCol = folder.Files;
    
    				// load everyting so we can access it
    				srcContext.Load(folder);
    				srcContext.Load(fileCol);
    				srcContext.ExecuteQuery();
    
    				foreach (SP.File f in fileCol)
    				{
    					// load the file
    					srcContext.Load(f);
    					srcContext.ExecuteQuery();
    
    					string[] parts = null;
    					string id = null;
    
    					if (srcLibrary == "My Files")
    					{
    						// these are doc sets
    						parts = f.ServerRelativeUrl.Split('/');
    						id = parts[parts.Length - 2];
    					}
    					else
    					{
    						id = folder.Name;
    					}
    
    					// build new location url
    					string nLocation = destWeb.ServerRelativeUrl.TrimEnd('/') + "/" + destLibrary.Replace(" ", "") + "/" + id + "/" + f.Name;
    
    					// read the file, copy the content to new file at new location
    					SP.FileInformation fileInfo = SP.File.OpenBinaryDirect(srcContext, f.ServerRelativeUrl);
    					SP.File.SaveBinaryDirect(destContext, nLocation, fileInfo.Stream, true);
    				}
    			}
    		}
    		catch (Exception ex)
    		{
    			Log("File Error = " + ex.ToString());
    		}
    	}
    }

    Best Regards,

    Dennis


    TechNet Community Support
    Please remember to mark the replies as answers if they help, and unmark the answers if they provide no help. If you have feedback for TechNet Support, contact tnmff@microsoft.com.

    • Proposed as answer by Patrick_Liang Wednesday, December 16, 2015 9:12 AM
    • Marked as answer by Patrick_Liang Monday, December 21, 2015 12:56 PM
    Friday, December 4, 2015 9:56 AM

All replies

  • Hi,

    Here is a blog for your reference:

    Copy a file across site collections with CSOM and REST

    http://sanderlesage.blogspot.jp/2014/07/copy-file-cross-site-collection-csom-rest.html

    Or the following code snippet for your reference:

    public static void CopyDocuments()
    {
    	var login = "<user@tenant>.onmicrosoft.com";
    	var password = "<password>";
    	string srcUrl="https://xxx.sharepoint.com/sites/site1";
    	string destUrl="https://xxx.sharepoint.com/sites/site2";
    	string srcLibrary="library1"; 
    	string destLibrary="library1";
    	
    	var securePassword = new SecureString();
    	foreach (char c in password)
    	{
    		securePassword.AppendChar(c);
    	}
    
    	var onlineCredentials = new SharePointOnlineCredentials(login, securePassword);
    
    	// set up the src client
    	SP.ClientContext srcContext = new SP.ClientContext(srcUrl);
    	srcContext.Credentials = onlineCredentials;
    
    	// set up the destination context (in your case there is no needs to create a new context, because it would be the same library!!!!)
    	SP.ClientContext destContext = new SP.ClientContext(destUrl);
    	destContext.Credentials = onlineCredentials;
    
    
    	// get the list and items
    	SP.Web srcWeb = srcContext.Web;
    	SP.List srcList = srcWeb.Lists.GetByTitle(srcLibrary);
    	SP.ListItemCollection col = srcList.GetItems(new SP.CamlQuery());
    	srcContext.Load(col);
    	srcContext.ExecuteQuery();
    
    	// get the new list
    	SP.Web destWeb = destContext.Web;
    	destContext.Load(destWeb);
    	destContext.ExecuteQuery();
    
    	foreach (var doc in col)
    	{
    		try
    		{
    			if (doc.FileSystemObjectType == SP.FileSystemObjectType.File)
    			{
    				// get the file
    				SP.File f = doc.File;
    				srcContext.Load(f);
    				srcContext.ExecuteQuery();
    
    				// build new location url
    				string nLocation = destWeb.ServerRelativeUrl.TrimEnd('/') + "/" + destLibrary.Replace(" ", "") + "/" + f.Name;
    
    				// read the file, copy the content to new file at new location
    				SP.FileInformation fileInfo = SP.File.OpenBinaryDirect(srcContext, f.ServerRelativeUrl);
    				SP.File.SaveBinaryDirect(destContext, nLocation, fileInfo.Stream, true);
    			} 
    
    			if (doc.FileSystemObjectType == SP.FileSystemObjectType.Folder)
    			{
    				// load the folder
    				srcContext.Load(doc);
    				srcContext.ExecuteQuery();
    
    				// get the folder data, get the file collection in the folder
    				SP.Folder folder = srcWeb.GetFolderByServerRelativeUrl(doc.FieldValues["FileRef"].ToString());
    				SP.FileCollection fileCol = folder.Files;
    
    				// load everyting so we can access it
    				srcContext.Load(folder);
    				srcContext.Load(fileCol);
    				srcContext.ExecuteQuery();
    
    				foreach (SP.File f in fileCol)
    				{
    					// load the file
    					srcContext.Load(f);
    					srcContext.ExecuteQuery();
    
    					string[] parts = null;
    					string id = null;
    
    					if (srcLibrary == "My Files")
    					{
    						// these are doc sets
    						parts = f.ServerRelativeUrl.Split('/');
    						id = parts[parts.Length - 2];
    					}
    					else
    					{
    						id = folder.Name;
    					}
    
    					// build new location url
    					string nLocation = destWeb.ServerRelativeUrl.TrimEnd('/') + "/" + destLibrary.Replace(" ", "") + "/" + id + "/" + f.Name;
    
    					// read the file, copy the content to new file at new location
    					SP.FileInformation fileInfo = SP.File.OpenBinaryDirect(srcContext, f.ServerRelativeUrl);
    					SP.File.SaveBinaryDirect(destContext, nLocation, fileInfo.Stream, true);
    				}
    			}
    		}
    		catch (Exception ex)
    		{
    			Log("File Error = " + ex.ToString());
    		}
    	}
    }

    Best Regards,

    Dennis


    TechNet Community Support
    Please remember to mark the replies as answers if they help, and unmark the answers if they provide no help. If you have feedback for TechNet Support, contact tnmff@microsoft.com.

    • Proposed as answer by Patrick_Liang Wednesday, December 16, 2015 9:12 AM
    • Marked as answer by Patrick_Liang Monday, December 21, 2015 12:56 PM
    Friday, December 4, 2015 9:56 AM
  • Hi Dennis,

    I did the same thing in PowerShell script and it copy files with metadata (except created by, created, modified by and modified) but not version history.

    $fileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($sRootCtx, $fileObj.ServerRelativeUrl);

    [Microsoft.SharePoint.Client.File]::SaveBinaryDirect($dRootCtx, $targetFolder.ServerRelativeUrl+ "/" + $fileObj.Name, $fileInfo.Stream, $true);

    I am trying to move files between sub sites from same site collection and it is required to retain all metadata including fields created by, created, modified by, modified and version history.

    I tried using below methods but no luck.

    [Microsoft.SharePoint.Client.MoveCopyUtil]::MoveFolder 

    [Microsoft.SharePoint.Client.MoveCopyUtil]::CopyFolder




    Tuesday, June 5, 2018 8:50 PM