Home About Contact Latest Articles Close

Recursively Copy Files Between OneDrive Accounts Using Azure Logic Apps

Author: Ofir Gavish

✨ What I Built

I built an Azure Logic App that recursively copies all files and subfolders from a folder in one OneDrive account to another, preserving the full folder structure and only copying files that have not been modified in the last 30 days.

πŸ”¬ Tech Stack

πŸ” My Goal

πŸ”§ How It Works

  1. Use a recurrence trigger
  2. Get root folder ID via metadata lookup
  3. Initialize variables for folder queue and current context
  4. Use an Until loop to walk folders recursively
  5. List children in each folder, append subfolders to the queue
  6. Copy eligible files with updated paths

🚫 Challenges I Faced

No folder trigger or folder metadata action

Logic Apps doesn't provide a dedicated trigger for changes in OneDrive folders, nor does it have a clear action named "Get folder metadata." I initially searched for a way to target folders directly but realized the available "Get file metadata using path" action also works for folders. Once I confirmed that folders could be treated as file items, I used this action with a path like / to retrieve the root folder ID and continue from there.

Path-based access failed

At first, I tried using folder paths (like /TSLog) in the Logic App to access subfolders. However, I consistently received 404 errors, even though the folders existed. The fix came from inspecting the Logic App's behavior in code view: I noticed it was using double-encoded OneDrive item IDs instead of folder paths. I switched the folder listing logic to use

encodeURIComponent(encodeURIComponent(id))
instead of a plain path, and it worked flawlessly.

SetVariable logic was out of order

In the Until loop, I was pulling the current folder values (id, name, path) from the foldersToProcess array. However, I placed the SetVariable steps before updating the array with skip(...). As a result, the same folder was processed repeatedly. I resolved this by placing the SetVariable steps after the array was updated with skip(variables('foldersToProcess'), 1), so each loop correctly pulled the next folder to process.

Array wasn’t updating

I used a Compose action to get the updated array of folders with @skip(...), but forgot to assign its output back to the foldersToProcess variable. Without that assignment, the array never changed, and I kept seeing the loop process the same folder repeatedly. I fixed this by adding a SetVariable step that stored the output of Compose into foldersToProcess.

lastModifiedDateTime was wrong

I tried filtering files based on a property called lastModifiedDateTime, assuming it was a standard field. This led to runtime errors because that field didn’t exist in the OneDrive metadata response. After checking the actual response from the OneDrive API, I found that the correct property was LastModified. I updated my condition to compare against that field, and the date filtering worked as expected.

πŸ“‚ Folder Structure Preservation

I added a path property to every folder in the queue and used that to recreate subfolders in the destination. Files are saved under /TSLogArchive/{relativePath}.

πŸ“¦ Full Code View on GitHub

You can find the full Logic App JSON here. Just update the OneDrive connections and root folder ID to make it your own.

🌟 Lessons Learned

πŸš€ What’s Next?

✨ Wrap-Up

This Logic App makes it easy to sync content between OneDrive accounts, fully automated and low-code. I hope it saves you time and effort. Contributions welcome!