The Problem
I've seen crop up in searches and I have seen it on Microsoft Tech community where people want to copy files somewhere for multitude of reasons but want to retain the created by and modified by information. Current methods do not retain information when a copy is used.
Existing Methods
Using a Power Automate Flow's built in "Copy File" copies files across sites and libraries no problem. However, the person triggering the flow or the account the trigger is built on becomes the created by / modified by after the copy completes since it's creating a new file for the copy.
The "Move file" action works, but it does not retain the original file in it's original location which is a requirement in many cases when copying files somewhere for archive or other purposes.
CreateCopyJobs to the Rescue
After looking around for REST calls that might work, I stumbled across the newer option which utilizes the same mechanics that "Move to" and "Copy to" use in SharePoint Modern pages. I thought originally that "Copy to" retained metadata but after testing it, it does not. I started looking at the properties for this call and noticed at the very end a property called "MoveButKeepSource"
public bool MoveButKeepSource { get; set; }
Once set, this move operation is similar to copy. The file will move to destination, but the source content will not be deleted. If set, this will make a copy with the version history and preserve the original metadata. No source item deletions occurs at the end.
Well, this is interesting. What this means is we can basically use the Move method but retain the original which in effect acts as a copy, but it will retain the metadata like a move to will. This is perfect! Now how do we get that into effect?
Here is a reference to the CreateCopyJobs Docs article.
The Flow
This is a very simple 2 step flow. Step 1 is the trigger, either a manual method using "For selected item" or you can have it automatically copy based on created / modified of files in a library. Step 2 is a "Send HTTP Request to SharePoint" action.
Below is my example flow that I used to get this working.
Here is the Body I used for this update, I hardcoded the destination and what not but if you need to make this dynamic for some reason you could easily do this. Just make sure you input your destination URL to the library without the trailing / as you will get an error if you include that.
Body:
{
"exportObjectUris":[
"Link_to_Item_Goes_Here"
], "destinationUri":"https://yourtenant.sharepoint.com/sites/your_site/Shared%20Documents",
"options":{
"IgnoreVersionHistory":false,
"IsMoveMode":true,
"MoveButKeepSource":true,
"AllowSchemaMismatch":true,
"NameConflictBehavior":1
}
}
I have the options set so that version history moves over, movemode tells this to use move instead of copy which will retain metadata, MoveButKeepSource is the key that keeps a copy and moves a copy. AllowSchemaMismatch is you have different columns in the libraries, I put this in as any changes to columns and you will get a badgateway error so best to have this in place. NameConflictBehavior is 1, this will replace existing files with the same name. If you want to create a copy instead you can specify a 2 and it will append a number to the end of the document name.
Conclusion
I hope this helps anyone out there that has this requirement of copying files somewhere and wanting to retain metadata from an automated method or you just want to copy files and retain the Created by / Modified by columns since utilizing the built in "Copy to" doesn't seem to do that.