Maintain file version history when moving/copying files between SharePoint sites

I’m working on a requirement to copy files from one document library to another document library in a sub-site. I figured this wouldn’t be horribly difficult to do but turns out it’s not as simple as you might think and for some reason, although I found many questions about how to do it, I found very few answers. From the things I’ve read out there it’s apparently relatively easy if you’re moving documents within the same site… apparently the Move method works and I read where someone suggesting using SPExport and SPImport. I also found a post by Ivan Sanders that said that you can use Site Actions > Manage Content and Structure > Choose the Library > Choose the docs >Use the Actions drop Down Click onMove > Choose the new Location to accomplish the move on this thread. Unfortunately, none of these solutions fully met my needs.

Ok, so onward and upward… I ended up started from a good post by ‘Dink’ on Copying documents between libraries with metadata – including version history which was a great starting point but seemed like it could be optimized a bit and was posted back in 2007, so I hoped that there might be potential improvements in 2010. As it turns out there is, in the form of additional overload methods for SPFileCollection.Add

So here’s my code snippet. I’ll point out that this snippet is in a function that takes two parameters SPListItem itmSource which is the source item to move, and SPDocumentLibrary libDest which is the target document library.

Published by

Julie Turner, MVP

Julie has been building software on primarily the Microsoft platform for over 20 years. With a degree in Electrical Engineering specializing in microprocessor system design from Worcester Polytechnic Institute she came at software initially from a very low level but quickly realized a love and aptitude for developing rich user experiences and solutions. She worked her way up through internal IT ranks reaching a Director of IT position before realizing more impact could be made in consulting and really focused in on the SharePoint platform in 2007. Since then her focus has been on the SharePoint platform, Office 365, Azure, and client side development. She's the co-author of the Widget Wrangler JavaScript library and continues to try and help innovate SharePoint and Office 365 solutions for her clients. She is a 2017 recipient of the Microsoft MVP award for Office Servers and Services.

33 thoughts on “Maintain file version history when moving/copying files between SharePoint sites”

  1. Dan,
    Not sure I understand what you mean. You’re saying that even thought the code sets the ModifiedBy metadata if it’s the second time it’s been moved by the code that piece of metadata will be missing on the second move? Only that one or others as well?

  2. Sorry Julie,
    The MoveTo method maintain version history (in the same site), and not between different sites.
    Thanks for your post.

  3. Ali, That’s not true…
    The MoveTo method does not maintain version history on a per version base.
    It does remember the correct metadata for the “current version”…

  4. MoveTo does not maintain version history. It does maintain the correct metadata for the “current version”. But every seperated version metadata is lost.

  5. Another way to copy or move document between Site Collection is use: SPExport and SPImport (keep all the versions, metadata, properties …)
    A bug in:
    bolMajorVer = fileSourceVer.VersionLabel.EndsWith(“0”) ? true : false;
    -> bug if the version of document like this: 0.10; 0.20
    It should be EndsWith(“.0”).
    Another way to check a fileVersion is Major or not is (fileSourceVer.Level == SPFileLevel.Published)

  6. hi,
    Your post is very useful but i’v got the following error :
    [ArgumentException: user
    Parameter name: Specified value is not supported for the user parameter.]
    Microsoft.SharePoint.SPFileCollection.ValidateUser(SPUser user) +26681329
    Microsoft.SharePoint.SPFileCollection.AddStreamInternal(String urlOfFile, Stream stream, Boolean bIsMigrate, Boolean bIsPublish, Boolean bcheckRequiredProps, Boolean bAutoCheckoutOnInvalidData, Boolean bForceCreateVersion, String lockIdMatch, SPUser createdBy, SPUser modifiedBy, DateTime timeCreated, DateTime timeLastModified, Object varProperties, String checkinComment, Boolean bOverwrite, Stream formatMetadata, String etagToMatch, Boolean bSyncUpdate, SPVirusCheckStatus& virusCheckStatus, String& virusCheckMessage, String& etagNew) +227
    Microsoft.SharePoint.SPFileCollection.Add(String urlOfFile, Stream file, Hashtable properties, SPUser createdBy, SPUser modifiedBy, DateTime timeCreated, DateTime timeLastModified, String checkInComment, Boolean overwrite, Boolean requireWebFilePermissions) +351
    Microsoft.SharePoint.SPFileCollection.Add(String urlOfFile, Stream file, Hashtable properties, SPUser createdBy, SPUser modifiedBy, DateTime timeCreated, DateTime timeLastModified, String checkInComment, Boolean overwrite) +91
    Any idea ?
    Thanks

  7. Hi Thomas,
    Unfortunately without context it’s hard to say, but based simply on the error I would say you’re passing in something into one of the user field that it doesn’t like. Maybe not the right type. if you posted the line of code that it was erroring on I might be able to help you further.

  8. For me the code was falling over on:
    fileDest.Publish(strVerComment);
    Turning on minor versions on the list got this to work for me.

  9. A late response, but it might help someone else.
    Are you trying to copy between different site collections? In that case, you need to ensure that the user exists on the target. SPFileCollection.ValidateUser(SPUser user) throws if user.SiteId != SPFileCollection.Web.Site.ID, which it won’t be if you’re trying to copy between site collections.
    Example:
    var webDest = libDest.ParentWeb;
    SPUser userCreatedBy = webDest.EnsureUser(fileSource.Author.LoginName);
    You will need to do the same for userModifiedBy.

  10. Hi there!
    I use your codesnippet. It works fine except for one thing: after a file is published (fileDest.Publish(strVerComment);), the “Modified”-Date is changed to “now” (current date with current time).
    Do you know any way to overwrite that value (listItem[“Modified”] = oldDate;) after it has been published?
    I tried the following methods but always failed:
    – listItem.SystemUpdate(false);
    – listItem.UpdateOverwriteVersion();
    Thanks for any help! Regards, Guido

  11. Glad you found something that worked for you. My only “good” suggestion if you had needed minor versions (which was my assumption based on your request) that you create a separate Modified date field and update it as appropriate.

  12. Hi Juile,
    Thanks for writing such wonderful blog related to version history in SharePoint.
    I have used same guidelines what ever you have given regarding how to copy all document versions from one library to another library with specific Content/Document.
    But my code is not working properly it giving error like ,
    System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
    at Microsoft.SharePoint.SPGlobal.HandleUnauthorizedAccessException(UnauthorizedAccessException ex)

    I am really confused about this why it is giving such error which is out of my thinking power.
    I have used this method of SPFileCollection class,

    at Microsoft.SharePoint.SPFileCollection.Add(String urlOfFile, Stream file, Hashtable properties, SPUser createdBy, SPUser modifiedBy, DateTime timeCreated, DateTime timeLastModified, String checkInComment, Boolean overwrite)

    Could you please give some guidelines regarding same…
    Hope so I will get positive feedback from you.
    Thanks,
    Nitin

  13. Hi Nitin, I’d like to help but I would need more information, like what line your getting the error on. Also, what type of scenario are you using to execute your code, event, workflow action, timer job, etc? Are you sure the account that you’re running under has access to both the source and the destination web. Are the webs in the same farm, in the same web app?

  14. Hi Julie,
    Thanks for reply,I am using this code in Event Receiver.I am copying the document with version from source to destination, these both are in same web app. The user have access to site collection but limited(Contribute) privileges.When I do the same process with Administrator credentials it is working fine.Users having Contribute permissions it is giving error mentioned above.
    I have also tried with RunWithElevated Privileges the result will be the same error.
    Please suggest me the way to avoid this error.
    Thanks
    Nitin Jagtap

  15. Hi,
    I have the same problem as Nitin. It is just as described. The problem arises when the user is a contributor.
    Did you find a solution?
    Thanks,
    Oliver

  16. Hi Julie,
    Thank you for your post; it gives me hope that I can meet my team’s requirements.
    I am wondering if you’ve heard of/interacted with anyone trying to realize this functionality in Sharepoint Online?
    I assume you’re working with direct access to a server that, at your original time of posting, was running SP2010. Now, it seems like a lot of the powershell commands are unavailable in SPOnline:
    https://technet.microsoft.com/en-us/library/fp161364.aspx
    Also, I am looking to automate the version maintenance as part of a larger approval workflow.
    Any, any, any info at all would be appreciated!

  17. developed the code in Dev and works great, published on a different environment am getting User Not Found exception. Moving within the same site from libA to libB.
    User cannot be found.Stack Trace :
    at Microsoft.SharePoint.SPUserCollection.get_Item(String loginName) on userModifiedBy = (i == 0) ? userCreatedBy : fileSourceVer.CreatedBy;

    any thoughts?

    1. Sorry, not without more information on what’s in those variables… I would honestly break that line up and look at what the exact values are. Probably just trying to do something with a Null or something

  18. Hi Julie,

    I have been searching for this functionality. Your code seems to do everything that I want.
    As I am not a programmer or developper…. how do I use this code. What are the steps I have to take if I want to move a document from source library to destination library???

    1. Ferry Martens,

      So, this code is meant to be used by a developer and isn’t really functional to be used any other way. If you want to move document from a source library to a destination library there are a few solutions, but assuming you want to maintain history you’re going to need to use a third party tool like ShareGate.

      -Julie

      1. I see, then I am in the wrong place. In the meantime I am testing the third party tool CopyMove2013. Also does the job.

Leave a Reply