Power Automate – How to move SharePoint Online list items to folders

Let’s say you have a SharePoint list with folders organized by continent and you have as well a choice column with the continent name in this. You want to move automatically all the list items with the chosen continent to the specific continent folder.

Capture1-768x502

The first idea would be to use a Power Automate Flow to do that, but there is no out-of-the-box action that moves list items to folders. At the moment of writing this post, there is an action to move files but nothing for list items. Even thinking about using SharePoint Rest API with the ‘Send an HTTP request to SharePoint’ connector there is no endpoint to move list items to a folder.

This is not clear in the Microsoft documentation, but actually, the same Rest API endpoint and action that is available for files can be used for list items by using the item file property. In this post, it will be shown how to use SharePoint Rest API to move items with a Flow, so as soon as an item is created or edited, it will be moved to the right location.

Basically, this Flow will do after being triggered:

1.   Get current list root folder path

2.   Get current item file name and the current path

3.   Build a new file path

4.   Check if the path is actually new and if so move the item

To better understand the following steps, knowledge on SharePoint Rest API and Flow expressions is helpful.

To start building the flow, the trigger used is ‘When an item is created or modified’.

In this example, variables are used to store the list title, destination folder name and the site Url. Because the same values will be used in different connectors, it is a better practice to not let them hard-coded in the actions. For example, if this flow is exported to another environment or copied to be used in a different list, the changes to the flow will be minimal, only the initial variables and the trigger, instead of updating a bunch of connectors with hard-coded values.

Capture-768x815

Next step is to get the list folder Url using the SharePoint Rest API, using the ‘Send an HTTP Request to SharePoint’ action with the GET method. The action was renamed to ‘GetRootFolder’ so it is easier to access its output later in expressions. All the variables actions in this example are renamed as well, just for easier maintenance.
getrootfolder-768x301

After this action, a new variable is initialized to store the list root folder Url with the following formula (use expressions to access the JSON content that is returned by the SharePoint Rest API, with the body function and the action name you can access the content):

body(‘GetRootFolder’)[‘d’][‘ServerRelativeUrl’]

rootfolder-768x210

Next action is to get the current list item File Server relative Url using SharePoint rest API like it was done with the list Root folder. In this case, it is needed to explicitly tell the Rest endpoint to load the ‘FileRef’ and ‘FileLeafRef’ properties.

getitem

The following variables are used to build the new list item folder Url, so the below formulas are used to assign values to the proper variables:

  • Item file name (Set with current file name only, used to build final destination path): body(‘GetItem’)[‘d’][‘FileLeafRef’]
  • Item Url (Set with current item server relative Url, using the expression): body(‘GetItem’)[‘d’][‘FileRef’]
  • New item Url (Root Folder/New Folder/Item File Name): concat(variables(‘RootFolder’),‘/’,variables(‘MoveToFolderName’),‘/’,variables(‘ItemFileName’))

itemvariables-768x766

Then, the SharePoint ‘Send an HTTP connector to SharePoint’ is used again, to call the Files REST endpoint and move the item to the new location (yes, the same endpoint used for files).

It is validated if the File new folder path is different then the current one:

moveitem3-1024x231

If it is, then a call to the API for the File/moveTo method is done in order to do the move:

moveitem2-768x343

This time a POST request is sent because we actually will request a change in this call to the endpoint, which will take care of the item move (also renamed the action to ‘MoveItem’).

After this last action is called, the item is moved to the proper folder.

The final flow will look like this:

CaptureFinal-1

With this flow, regardless of where the items are saved, they will be moved to the proper folder after being created/edited.

49 comments

  1. Apenas para complementar: da para usar a api “_api/SP.MoveCopyUtil.MoveFileByPath()”. No corpo da requisição da para passar o seguinte JSON:

    {
    “srcPath”: {
    “__metadata”: {
    “type”: “SP.ResourcePath”
    },
    “DecodedUrl”: “https://seutenant.sharepoint.com/sites/seusite/Lists/sualista/21_.000”
    },
    “destPath”: {
    “__metadata”: {
    “type”: “SP.ResourcePath”
    },
    “DecodedUrl”: “https://seutenant.sharepoint.com/sites/seusite/Lists/sualista/NOVA_PASTA/21_.000”
    },
    “options”: {
    “__metadata”: {
    “type”: “SP.MoveCopyOptions”
    },
    “RetainEditorAndModifiedOnMove”: true,
    “ShouldBypassSharedLocks”: true
    }
    }

  2. Hi,

    Thanks you for the detailed post, its exactly what I’m looking for. I’m just having the following error messages on the Initialize variable – ItemFileName & Initialize variable – ItemURL

    Correct to include a valid reference to ‘GetItem’ for the input parameter(s) of action ‘Initialize_variable_-_ItemFileName’.

    Correct to include a valid reference to ‘GetItem’ for the input parameter(s) of action ‘Initialize_variable_-_ItemURL’.

    Any help would be great. Thanks!

  3. Thanks for this sample, however the getrootfolder action is now gone in power automate, may I know what is the new one? I couldn’t follow this sample anymore.

    1. It’s the ‘Send an HTTP Request to SharePoint’ action…I just renamed it to make the logic clearer..

  4. Hi Michel, thank you for the post. Is it possible to move the list item to a different list instead? The reason being I do not want to use the “Get Item” and “Create Item” actions to copy the item as this requires the fields to be manually mapped. In the future, if a new field is added, I do not want an individual to have to go in and add the new field to the “Create Item” action. I am able to use the method you describe above to move the item from List A, however the item is not being moved to the correct destination. Can you help with the Uri I should be using to move the list item into another list? Thank you in advance for any help.

    1. Hi Jonathan,

      There’s no way to move list items to a different list with a single API call…But you can use the rest endpoints and some tricks to get it done:

      1) Retrieve the custom fields names on the list:
      _api/web/lists/GetByTitle(‘Your List title’)/fields?$filter=CanBeDeleted eq true
      2) Get the current list item value:
      _api/web/lists/GetByTitle(‘Your List title’)/Items(Your Item ID – Number)
      3) Use some advanced JSON manipulation to get the fields you would copy and create a new JSON String with the content
      4) Then add it to the second list using the items endpoint and the POST method:
      _api/web/lists/GetByTitle(‘Your Second List title’)/Items

  5. Thank you for sharing these steps! I was able to combine them with some info on another site in order to move a file into a folder structure 3 levels deep. The one thing that was causing an issue for me was in the last MoveItem step – I had to zoom in a lot on your screenshot in order to tell whether it was a comma or a period in front of =flags=1… If anyone else is curious, it’s a comma! Now the flow works for me and I’m really excited. Thanks again!!

  6. Hi Michel, greetings. I need some guidance. One of my teams (relatively new) have moved some records from one list to another using some .NET code provided by the vendor who transitioned the SharePoint to us before they quit. We have not tested it or used it until a week back, when we wanted to move some records (which also contained some attachments) to another library. It was more like moving historical data to another library while maintaining new records in the current library. When we executed the script, the records have moved to the destination, while the attachments were not moved. This was also not reported in the error log. As this action was done to free up some space, our team “manually” deleted the records from the site collection recycle bin. When we tested in the new list, we can see only the records but not the attachments. Do we have a way to restore the “attachments” as they are now completely missing for all the records that were moved to the new destination? Could you provide us some guidance on how can we retrieve the attachments? I would be happy to get connected with you via your Forum/Blog. Thanks in advance for your time to read this and also any support you may provide us that can help us retrieve the attachments which are very important.

    1. Hey Ragavan,
      Were the files deleted even from the second stage recycle bin? If they weren’t you can try restoring them from there.
      Otherwise, if you are using SharePoint Online I recommend that you open a support ticket with Microsoft, they may be able to restore the full site collection (it depends on when the changes were made)…

  7. Hi there,

    Great blog post. Just wondering, is it possible to use the action “For a selected item” instead and also in my case, I just want to move the item to a folder called archived, that is on the same list. Is it possible for the above to be shortened?

    Basically I am just looking for a way where it easy for someone to archive a item in a sharepoint list into a folder.

    Cheers

    1. Hi Daniel,

      Yes, on the example above, you will need a few replacements:
      1) Use the for a selected item trigger
      2) In the HTTP action where you get the item data, use the ID retrieved from your new trigger
      3) Where we set the variable ‘MoveToFolderName’, put your ‘Archive’ folder name hardcoded there as it is fixed. You can keep it in the variable so it’s simpler to change to something dynamic later if needed.

      Hope this helps

  8. How would you do this if you do not currently have a folder in place that you need to move the item into? In other would create a new folder if it doesn’t already exist

    1. Hi Kevin,

      Before moving the item, add two additional actions:
      1) ‘Get folder metadata using path’, using the folder path you would move the item to
      2) Create new folder (using the selected list and folder name only as values)

      On the ‘Create new folder’ action settings, configure it to run after ‘Get folder metadata using path’ failed’ (it will fail in case the folder does not exist) (You could add more logic here to validate the errors better but in summary it will be trigger by the ‘Get folder metadata using path’ action failing first…

      On the ‘Send an HTTP request to SharePoint’ action to move the item, configure it to run after ‘Get folder metadata using path’ is skipped OR is successful.

  9. Hi Michael,
    Thanks for that flow, it’s exactly what I needed!
    However on the Initialize variable – RootFolder step, I get the following error:
    “Unable to process template language expressions in action ‘Initialize_variable_-_RootFolder’ inputs at line ‘1’ and column ‘10366’: ‘The template language expression ‘body(‘GetRootFolder’)[‘d’][‘ServerRelativeUrl’]’ cannot be evaluated because property ‘d’ cannot be selected. Property selection is not supported on values of type ‘String’. Please see https://aka.ms/logicexpressions for usage details.’.”
    Can you please advise on what might be the issue?

      1. Hello,

        Thank for the step by step instructions. I received the same error as Rositsa. I have followed your instructions and I have not added any headers as per your screen shots.

        Can you please share git location or can you send an export copy of this flow?

  10. Thank you for the post. I’m trying to get it run, but I keep getting an error regarding FileLeafRef. I appreciate any help you can provide on this.
    Unable to process template language expressions in action ‘Initialize_variable_-_ItemFileName’ inputs at line ‘1’ and column ‘10618’: ‘The template language expression ‘body(‘GetItem’)[‘d’][‘FileLeafRef’]’ cannot be evaluated because property ‘FileLeafRef’ doesn’t exist, available properties are ‘__metadata, FirstUniqueAncestorSecurableObject, RoleAssignments, AttachmentFiles, ContentType, GetDlpPolicyTip, FieldValuesAsHtml, FieldValuesAsText, FieldValuesForEdit, File, Folder, LikedByInformation, ParentList, Properties, Versions, FileSystemObjectType, Id, ServerRedirectedEmbedUri, ServerRedirectedEmbedUrl, ID, ContentTypeId, Title, Modified, Created, AuthorId, EditorId, OData__UIVersionString, Attachments, GUID, …

  11. Works perfectly now. I figured out my error. I had a line feed in the “GetItem” step between the “?’ and the select statement. Thanks again for the post.

  12. Hi, very good solution and most of the steps work well. Unfortunately, I always receive the error message

    A potentially dangerous Request.Path value was detected from the client (*).
    clientRequestId:….
    This is the URI and it looks as it can get the respective item.
    _api/Lists/GetByTitle(‘testtest’)/Items(50)$select=*,FileRef,FileDirRef,FileLeafRef

    I already searched google and the url of the list does not contain any invalid characters. Is ther any chance to modify the GetItem step to load the ‘FileRef’ and ‘FileLeafRef’ properties that the command will work?

    1. Hi,

      It should work, this error happened because you forgot the question mark before $select.
      Try: _api/Lists/GetByTitle(‘testtest’)/Items(50)?$select=*,FileRef,FileDirRef,FileLeafRef

  13. Hi Michel, this was great, thank you! Question, what additional steps would be needed if the item was already in a folder and wanted to move into another folder (2 levels deep from main list, so item is in folder A, but needs to go to folder B inside A)? Folder B name is fixed, so I tried to put in variable ListTitle (NameofList) or GetRootFolder, but got the following error on GetRootFolder –

    The expression “Lists/GetByTitle(‘NameofList’)/(‘FolderA’)/RootFolder” is not valid.

    Thanks!

    1. Hello David,

      Use the expression “Lists/GetByTitle(‘NameofList’)/RootFolder” as stated in the post and then manipulate it in a variable or compose action, so it gets your subfolder folder in the end. This root folder action gets the root folder of the whole list.

      Example (you can copy and paste this in a compose or set variable action, if you have the ‘RootFolder’ variable set as in this post):
      @{variables(‘RootFolder’)}/Folder A/Folder B

  14. Hello, the getfolder lead to error for me

    body”: {
    “status”: 401,
    “message”: “401 UNAUTHORIZED\r\nclientRequestId: 002f9b77-12a7-4a14-aff2-6e239f78efdb\r\nserviceRequestId: 10bc18a0-0032-3000-b457-3c2e420ba6b4”,
    any idea what could lead to this ?

  15. Hi Michel,

    This is amazing, thank you so much for sharing! I’m running into an issue with the URL name’s not matching and I have some strange numbering in my URL.

    Source URL: https://mysharepointsite.com/sites/HotDesks/Lists/SupplierHoldView/AllItems.aspx?id=%2Fsites%2FHotDesks%2FLists%2FSupplierHoldView%2FFOODPACK&viewid=cf260aa3-8498-45d1-a33d-525cad22837c

    URL outputted by Power Automate: /sites/HotDesks/Lists/SupplierHoldView/FOODPACK LTD

    I assume it’s an issue on my side with how I’ve setup the SharePoint site but any help would be greatly appreciated!!

  16. Hi Michel, ignore my comment…it is all working perfectly…I am just stupid and spelled a folder name incorrectly 🙂

  17. Great Post – Just what I need but I am getting an error when attempting to use the api call.
    Any ideas why the resource is not found?
    “status”: 404,
    “message”: “Cannot find resource for the request getFileByServerRelatedURL.\r\nclientRequestId: 6e814293-bf10-4e64-9639-5b264b7935c0\r\nserviceRequestId: 187030a0-b0a8-c000-e9a2-336e5cd5cd32”,

    1. Hey Wesley, is there any special character in your file path? What is the value you are trying to access for the path?

  18. Hello I have this error
    La expresión “Web/getFileByServerRelativeURL(‘/sites/Administracion/Lists/Text Text Text/151_.000′)/moveTo(newurl=’/sites/Administracion/Lists/Text Text Text/Text/151_.000’,flags=1” no es válida.
    can you help me, please?

  19. Thank you very much for your great work!
    I downloaded the package and wanted to customized it. May I ask what should I input for ComposeItemURL and ComposePathToItem?
    In addition, I want to move those list items that have completion status has been modified to “Yes”. Where can I apply such condition in your flow?

    1. Hey Ning,

      ‘composeItemURL’ is the full URL that redirects to opening a list item, such as:
      https://contoso.sharepoint.com/sites/SPFxDevLegacy/_layouts/15/listform.aspx?PageType=4&ListId=5547c495%2Df247%2D4e75%2Dad06%2Dbfeac1c43675&ID=8&ContentTypeID=0x010043A6B90A84CF864498D7DCE14BB79F57

      ‘composePathToItem’ is only the path from the root site to the folder, such as:
      Lists/FormsTest/8_.000
      This is what we use to get the URL to be moved

      To apply the condition for your field and trigger the flow only when the field has the value of ‘Yes’, you can modify the trigger condition with an AND or OR condition, depending on your rule

      The below works for a choice field:
      @and(equals(triggerBody()?[‘{IsFolder}’],false),triggerBody()?[‘YesNoChoiceField’]?[‘Value’],’Yes’)

      The below works for a boolean field:
      @and(equals(triggerBody()?[‘{IsFolder}’],false),triggerBody()?[‘YesNoBooleanField’],true)

  20. Hey Michel. Thank you very much for the article! I am using the Flow template you uploaded to GitHub, but have an issue. When a new item is added to my SP List using PowerApps, it is not until another item is added that the previous item is placed into the corresponding folder. Any advice/insight on this? Thanks!

    1. Hey Rob, the flow might have a delay being triggered, up to 5 minutes….Then it will run and the item will be moved. Isn’t that your case?

  21. It’s 2024 and yours is the gift that keeps on giving.
    I had no issues following your instructions and adapting it to my use case.
    It’s rather remarkable that you are pretty much the only source on this matter for all these years.
    Quite inspiring.

Leave a Reply

Your email address will not be published. Required fields are marked *