Musings and Solutions for SharePoint, O365, and Azure

2010 SPDocumentLibrary

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

June 2, 2011

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.

    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.

    1. nattuthurai

      hi Your post very useful.. Thanks, Nattuthurai.K

    2. Dan

      But it will lost ModifiedBy when move the file 2 times without modifying the metadata on editpage between this moves :(

    3. 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?

    4. Ali

      Julie, You can use MoveTo Method that takes an argument which is the URL of your target (http://anotherserver.....)

    5. Ali, Thanks for your reply. The MoveTo method can be used yes, but not if you want to maintain version history with it which was the point of the post.

    6. Ali

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

    7. 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"...

    8. MoveTo does not maintain version history. It does maintain the correct metadata for the "current version". But every seperated version metadata is lost.

    9. Pham Trung

      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)

    10. Thomas

      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

    11. 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.

    12. Stephen

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

    13. Emad

      Thanks for this article I had to change the code slightly for my own specific situation. Thanks so much

    14. Rajeev

      so there is no out of the box way on this in sharepoint 2010 and how to use ur code above ? please guide

    15. When moving the user info as well, User not found(say if user is removed from AD) error will spit out , how to handle this situtation?

    16. Jeroen

      I have the same problem, did you fix it already?

    17. 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.

    18. Guido

      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

    19. 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.

    20. 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

    21. 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?

    22. 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

    23. Oliver Lopez

      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

    24. Hassan

      Just wanted to thank you for this fantastic code sample. Works like a charm.

    25. Andy

      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: 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!

    26. Well, you're right about that this was code that was run against an on prem farm... for sponline you have a couple options, CSOM, JSOM, and REST, the most complete of these being CSOM. What I would suggest is you take this code and try and rewrite it using CSOM which would then work against SharePoint online... to be clear this is what mean...


      Thanks for that great code...

    28. 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?

      • 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

    29. Ferry Martens

      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???

      • 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

        • Ferry Martens

          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 comment

    Leave a Reply

    %d bloggers like this: