“Is it possible to synchronise files between 2 SharePoint document libraries with Power Automate, including the folder structure?”
There’s already a blog post how to copy files between libraries, even including the folder structure. But that was a full copy process, it takes all the files and folders and copies them. To keep two libraries synchronised you don’t want to replace all the files over and over again. You want to synchronise only the changes. If there’s a new file, maybe even in a new folder structure, it should be synchronised including the folder structure. The same should happen when a file is modified – the updated file should stay in the original path. And that’s what this post is about: how to synchronise files including their folder path?
Run the flow only for files
Start with the trigger ‘When a file is created or modified (properties only)’, and add a trigger condition to run the flow only for files.
@equals(triggerOutputs()?['body/{IsFolder}'], false)
This way you’ll simplify the flow. If you processed also the folders, you’d need two branches in the flow – one for files and one for folders. You can save one of the branches if you create the folders only when you need them, together with a file.
Copy the file
A file (not a folder) was created or modified, now it’s time to copy it. I prefer using the ‘Copy file’ action as you can easily replace the file if it already exists. This solution will replace the file, but you can also update it if you’d like.
Note: You could use also the ‘Create file’ action, but then you’d have to build the replace functionality by yourself.
The tricky part is to define the ‘Destination Folder’. While the trigger provides you the ‘Folder Path’ dynamic content, e.g.
Shared Documents/Folder/Subfolder/
it’s slightly different than what the ‘Copy file’ action expects. If you use the ‘Folder Path’, you’ll end up with an error message: “Failed to verify the existence of destination location at…”. That’s because the action needs the / character on the other side, the ‘Destination Folder’ must have the format below.
/Shared Documents/Folder/Subfolder
Add the opening / to the ‘Destination Folder’, and follow with an expression that’ll give you the path without the last /. It’ll take(…) the whole length(…) of the path without the last 1 character.
take(triggerOutputs()?['body/{Path}'],sub(length(triggerOutputs()?['body/{Path}']),1))
Create the folder structure (if needed)
Here comes the downside of the ‘Copy file’ action. If you used the ‘Create file’, it would automatically create the folder structure. With ‘Copy file’ this is the functionality that you must build (which I think is much easier than building the file replacement after ‘Create file’).
If the ‘Destination Folder’ doesn’t exist, the ‘Copy file’ action will fail. But that’s fine, the flow can continue even if an action fails. Add the ‘Create new folder’ action and configure it to run only if the ‘Copy file’ has failed. With this configuration it’ll run only if the folder structure doesn’t exist. If the folder structure exists, the flow will end with the ‘Copy file’ action.
Confirm the ‘run after’ configuration and go back to the action to configure it. The ‘Folder Path’ in this action is again different from the values before before. Since ‘Create new folder’ allows you to select the ‘List or Library’, you must remove the library from the folder path.
Full folder path
Shared Documents/Folder/Subfolder/
Folder path needed for 'Create new folder'
Folder/Subfolder/
That’s the job for the expression below: take the whole path, split(…) it by /, skip(…) the first result, and join(…) it back. It’s the same solution as when splitting string by the first space, only this time it’s /.
join(skip(split(triggerOutputs()?['body/{Path}'],'/'),1),'/')
Once the folder is created you can copy the file again with a second ‘Copy file’ action. If the first one fails, you’ll create the folders, and copy the file again.
Summary
The Power Automate flow above will synchronise files between two SharePoint libraries including their folder structure. It’s a bit more complex than needed as there isn’t any action in Power Automate that would do everything you need. ‘Create file’ would create the necessary folder structure, but it won’t replace existing files. ‘Copy file’ on the other hand can replace a file very easily, but doesn’t create any folders. Add the various inputs for the folder paths, and a simple functionality might need quite a complex flow.
And don’t forget to handle also the deleted files.
Hello Tom,
In the scenario where the source and the destination sites are the same, but the source and destination libraries are different inside the “take” expression what is the best way to cut the beginning of the folder path and add the name of the destination library ?
JLP
Hello JLP,
the easiest approach would be to split the path by the first / as described in this blog post: https://tomriha.com/how-to-split-string-by-the-first-space-in-power-automate/
Hi Tom –
This is a great post and I have it working well (can’t thank you enough!). Although I have an issue that you may know how to handle. How do you trigger when a file has been moved from one directory or another in the monitored directory or any of it’s subdirectories. The trigger is executed perfectly if a file is created or modified, but nothing happens when it is moved.
Thank you for all your work!
B
Hello Brian,
unfortunately I don’t have a solution for that, Power Automate just doesn’t recognise moving files as an update.
Hi Tom,
Thank you for your reply! Apologies that I just saw it. Don’t know what happened there…
I think I have found a partial solution to what I’m working on. I have setup a “When a file is Deleted” trigger using the principles described in this post. Unfortunately, I can’t figure out how to get the directory information (path) of the file that is being deleted. I can get the file name/extension fine but no directory info. Is there any way to get that?
Thank you again for these great posts!
B
Hello Brian,
you can’t get a path from a deleted file, but you can get the file name which you can use to search for the file in the second library (https://tomriha.com/power-automate-to-filter-file-in-sharepoint-by-file-name/) and delete it (or get the path of the file in the second library which will be the same as the file that was just deleted).
I’m trying to do a 1-way sync between SharePoint folders in different Libraries on the same SharePoint site. If I can get that to work reliably then I’d like to try doing a 2-way sync. I think the steps outlined above will sync 1-way when a file is added or modified in Site 1. But will it delete files in Site 2 that are deleted from Site 1?
Hello Steve,
take a look on the new post: https://tomriha.com/handle-deleted-files-in-synchronised-sp-library-in-power-automate/.
So I have implemented this and i see 2 issues.
when creating a new folder in the source document library, the folder gets created in the destination, but it is created twice.
example. Source > FolderA created > DocA created
Destination > FolderA created > FolderA created > DocA created
issue 2:
when moving a folder (with documents) to another location in the source SP docu library. The rule is not getting triggered to create the folder and files in the destination SP docu library.
thoughts?
Hello Todd,
I’d check the flow run history and the input of the ‘Copy file’ action – if it creates a deeper folder structure then the folder must be used twice somewhere, maybe in the take(…) expression…?
Moving files between folder or libraries is not considered a file update by Power Automate, it won’t trigger flow on such event unfortunately…
did you find a solution for the duplicating folders?
Hi Tom,
thank you for your help. I have the same issue asTodd Voelcker.
When creating a new folder in the source document library, the folder gets created in the destination, but it is created twice.
I’ve done everything correctly. I’ve just struggled to put a / in front of the “take” expression because it disappeared everytime. Finally I managed but maybe this is the problem….do you have any suggestion to put / in front of an expression in a correct way?
Thanks
Hello Gianluca,
the flow would probably return an error if there was something wrong with the / character. I don’t like to deal with folders as they’re often problematic, especially if it’s subfolders (as explained in another article: https://tomriha.com/how-to-copy-sharepoint-files-including-folder-structure-in-power-automate/).
I’d recommend using the solution only for files as intended where it’ll create folders only when needed with the assumption that you don’t need to synchronise empty folders.
If the file name is changed in the source location I end up with the original file and the new file in the 2nd location.
Is there an elegant solution for this?
I really want them to act like a “sync”
thanks
Hello Amy,
that’s a tricky one as once you rename a file you’ll lose the original information to search for the file in the second library. The first workaround I can think of is to add an extra “backup” column in both libraries to store some shared identifier, e.g. id of the file in the original library and then search for the second file using the id.
Hi Tom, this has been working well for copying my folder structure over, but my file fails every time, it says ‘failed to verify existence of destination location’, even if there is no structure to carry over (failing on the first copy file), On the destination url it’s getting my destination and source sites mixed up, it’s trying to copy the file to my destination site but the library from my source site. Any idea why this is happening?
Hello Mark,
no idea, that’s some strange behaviour. If it doesn’t remember what libraries you selected in the dropdown you can try to add a few ‘Compose’ actions before the ‘Copy file’, store the SP sites/libraries in these ‘Compose’, and use the outputs to copy the file. But it shouldn’t happen in general, something must’ve been wrong with the flow engine.
Hi Tom,
Thank you for this post. I’m having problems with the
take(triggerOutputs()?[‘body/{Path}’],sub(length(triggerOutputs()?[‘body/{Path}’]),1))
expression. It gives me this error:
InvalidTemplate. Unable to process template language expressions in action ‘Move_file’ inputs at line ‘0’ and column ‘0’: ‘The template language function ‘length’ expects its parameter to be an array or a string. The provided value is of type ‘Null’. Please see https://aka.ms/logicexpressions#length for usage details.’.
Any thoughts?
Hello Jimmy,
it’s telling you that the triggerOutputs()?[‘body/{Path}’] doesn’t contain anything – I’d check the trigger action and look for the {Path} property, maybe that’ll tell you more.
I was working for moving file from source library with folder structure to destination library with the steps given above work fine for me up to create new folder step. Instead of using take (….) expression in destination folder, I used full path from the create folder option and it is working fine for me.
I’m trying to copy new files or update existing files so content in several geolocation tenants stays in sync. The idea is a user can upload or update a file in the US organizational assets site and the Flow will either copy or update the corresponding files in the geolocation sites. I’ve tried various options, and your solution here results in this error on the copy file action:
Copy or move can’t rename or replace an existing item at the specified destination location.
Hello Matthew,
you can use Power Automate flows with the default actions only in a single tenant, for connecting to another tenant you’d have to use an HTTP request that would authenticate towards that tenant and transfer the file, which will require a registered Azure application – a bit more complicated flow than the one explained.