SharePoint Experts Blog

How to move documents using workflow in SharePoint 2013 and Office 365

In this article I will show how to move documents using SharePoint 2013 workflows. This approach works well for SharePoint 2013 on premise deployment as well as for SharePoint Online in Office 365. I will implement archival workflow as a proof of concept, which moves documents from one document library to another, but you can modify it a little and use to copy documents or folders cross-site.

As you probably know, you can store many documents in the SharePoint document libraries. For SharePoint 2013 it is 30 000 000 per library. However, there is another limit which spoils all the fun, it is list view threshold 5 000 documents or list items. There are also another limit, like security scope limit, which doesn’t allow to have more than 50 000 security scopes. Roughly speaking it is amount of documents or folders with unique permissions. You can find full list of list and library limits on technet.com.

As result it is not always possible to store 30 000 000 documents in the single document library. So, we have enough reasons to think about setting up archival workflow which will move outdated documents to archival document libraries. Thus, we will eliminate the issue with large amount of documents in the document library.

I will show how to set up periodical archival process, which will run monthly. This workflow will create new document library and move documents created during the previous month into this document library. The workflow produces the structure of libraries like this:

 

I have single document library ‘Documents’ where I work, once per month the workflow creates new document library and names it using such pattern ‘Archive – {YEAR} {MONTH}’.

My document library has plain structure without folders, I use metadata navigation by project and by department instead of folders. I added two metadata columns into document library ‘Project’ and ‘Department’. You can see how it looks below:

To implement archival workflow with such functionality, I have to be able to create new document libraries by custom template, because I have two metadata column in the library. I also need to query documents using CAML query, because I have to archive documents created in the last month only. To create document library I need to generate appropriate name using template ‘Archive – {YEAR} {MONTH}’. Then I have to move documents which I received from CAML query into created document library. In this example I work within the same SharePoint site, but I want to have possibility to move documents cross-site. Finally I need to schedule the archival workflow to run periodically.

Out of the box workflow actions don’t allow to implement even half of such functionality. In this example I will show how to use some workflow actions from Workflow Actions Pack to implement the workflow and how to schedule the workflow using Workflow Scheduler.

Archival workflow configuration

 
 
I created one site level workflow named ‘Move to archive’. It consist of five stages:
  • Setting credentials
  • Querying documents
  • Generating new library
  • Moving documents
You can see the stage outline for the workflow below:
 
 
 
 
As you can see, there is stage transition condition after ‘Querying documents’ stage. In this conditinon I check if any documents for archiving found. If there are no documents, the workflow will be completed.

Full schemes of the workflow:

Take a look at documentation to get more information about properties of workflow actions used in this article.

Before we dive in, also take a look at workflow variables of the archival workflow:

 

Setting credentials stage

At this stage I just saved credentials which I use within workflow actions in workflow variables. This step is actual for SharePoint Online in Office 365 only. If you use SharePoint 2013 on-premise you can go to the next step.

You can see text-based view of this stage below:

 
 

Querying documents stage

At this stage I used two custom workflow actions:

  • Format date – allows to format dates using format string. You can find description date format strings on MSDN.
  • Get items by query – allows to query documents using CAML query.

You can see text-based view of the stage below:

 
 

At this stage I used ‘dd’ format string which allows to get day number. I needed this to build CAML query which could return documents from the previous month only except documents created in the current month.

This is how CAML query looks:

<View>
    <Query>
        <Where>
            <Lt>
                <FieldDef Name="Last_x0020_Modified">
                    <Value type="DateTime">
                        <Today OffsetDays="-[%Variable: CurrentDay%]"></Today>
                    </Value>
                </FieldDef>
            </Lt>
        </Where>
    </Query>
    <ViewFields>
        <FieldDef Name="Title">
        <FieldDef Name="FileRef">
        <FieldDef Name="FileLeafRef">
    </ViewFields>
</View>

As you can see I used -[%Variable: CurrentDay%] inside offsetdays of the CAML query. Note, there is minus (-) sign before CurrentDay variable. This allows the workflow action to query documents created earlier than Today – CurrendDay. So, I the workflow action will query all documents created earlier than current month.

I used this CAML query inside ‘Get items by query’ workflow action. This workflow action saves result in the dictionary workflow variable. Dictionary in SharePoint 2013 workflows can store collection of objects as well as single objects with key value pairs. You will see how to iterate through items in the dictionary at the last stage of the workflow.

As you see above, there is also condition in the transition section. It checks if no documents found, it completes the workflow without creation of new document library and without moving of documents.

Generating new library stage

At this stage I generate name for new document library and create new library.

Firstly I used ‘Add Time to Date’ workflow action to subtract one month from the current date to get date of the previous month. Then I used this date inside ‘Format date’ workflow action to get name for new document library. I used ‘yyyy MMM’ format string. It allows the workflow to generate string in the following format ‘{YEAR} {MONTH}’.

To create new document library I used ‘Create list or library’ workflow action. As I mentioned in the beginning of this article, I added two metedata columns into document library, therefore archival document libraries also have to contain such columns. To guarantee that archival document libraries will have such columns I saved source document library as template. To save library as template navigate to ‘Library Settings’ and click ‘Save document library as template’. I named the template as ‘Project Documents’. I used this template’s name in the workflow action as well as name generated in the ‘Format date’ workflow action. See text-based view of this stage:

 

One important note about configuration of ‘Create list or library’ workflow action. There is ‘ThrowError’ property and I set it to ‘No’, because I don’t want to interrupt the workflow if the document library already exists. You can find this property in workflow action’s properties:

 

Moving documents stage

At this stage the workflow iterates through documents received from the CAML query and moves them into created document library.

To move documents I used ‘Move document from library’ workflow action. Firstly I initialized the index variable. The workflow increments this variable in the loop. I used this variable to get values from dictionary with information about documents by index. You can see two workflow actions ‘Get an Item from a Dictionary’ in the text-based view below. I used them to get the URL and the name of the document from dictionary. To get value from current item of dictionary I use following paths:

([%Variable: ind%])/FieldValues/FileRef
([%Variable: ind%])/FieldValues/FileLeafRef

Paths has following format:

({INDEX})/FieldValues/{FIELD_INTERNAL_NAME}
The ‘ind’ variable stores current index within the loop. You can see how I used it on the picture below.
 
 
 

I used ‘FileName’ and ‘DocumentURL’ in the ‘Move documents from library’ workflow action. The ‘FileName‘ is required to build the URL of the new documents. To build the URL I used following combination of workflow constants and variables:

[%Workflow Context: Current Site URL%][%Variable: LibName%]/[%Variable: FileName%]

It is current site URL plus document library name plus file name.

Once we got all necessary information, it is possible to move documents using the workflow action. You can see how I configured the workflow action on the picture above.

Note: If you have structure with folders, you can use ‘Move folder from library’ workflow action.

Workflow scheduling

Scheduling of workflows is quite useful, especially for SharePoint Online in Office 365, because there is not any possibility to create custom timer job or something like this. To schedule the archival workflow I used Workflow Scheduler. I configured schedule to run the workflow at 6th day of each month. So, in the beginning of the month I still can use documents from the previous month, but at 6th day, if I didn’t use them, they will be moved to the newly created document library archive. As I described above, I created the workflow with possibility to change the schedule. Do you remember ‘dayoffset minus current day’? So it is possible to specify any other day to start the workflows. You can see configuration of the workflow scheduling task below:

 
 
 

Full schemes of the workflow

 
Click on the picture below to see visual designer view of the full workflow.
 
 
 
Click on the picture below to see text-based view of the full workflow.
 
 
 

Conclusion

In this article I showed how to implement archival workflow for SharePoint 2013 and SharePoint Online in Office 365. Now you know how to query documents from library using CAML and iterate through results,  how to create new document libraries by custom template and move documents from one library to newly created. Finally, you can schedule SharePoint 2013 and SharePoint Online workflows.

I hope this guide will be helpful and you will utilize much more functionality of SharePoint workflows. Should you have any questions, feel free to comment.

 

 

Posted in: Workflow Actions Pack, Workflow Scheduler

  • TonyR
    Anton I have just started reading this article as it’s very similar to something I’m trying to achieve. However it would seem that your example CAML query is missing so I’m not able to use this as a basis for my CAML query
  • BAL
    Anton I am interested in archiving inactive content across sites. I am thinking the workflow would trigger when a user indicates the file/folder Active field as “no”. Is there a simple way to archive content across sites? I am not familiar with CAML, but I’m not sure it is even necessary to accomplish this. Any direction you could give would be appreciated.
    • Hi BAL,There are two options in your case.The first. To configure site level workflow to query all files with field ‘Active’ equals ‘No’, then move it as described in this article. You can use Workflow Scheduler to start workflow once per day or more frequent. This workflow will be started periodically, find inactive items and move them. You can use CAML Query Helper tool to create appropriate CAML query: https://spcamlqueryhelper.codeplex.com/Your CAML query can look like this: 0The second. You can create list level workflow which will be started on list item change (it can be configured in SharePoint Designer). Each time on change you will check if ‘Active’ field is equals ‘No’. If it is, you will move this item to your archive.Personally I would prefer the first way. There is less possibility of error and you can track execution of archival process in one place (in site level workflow). In the second case the workflow will be started on each element and it will be difficult to track execution.
  • Jason Heiser
    Are you using a 2010 workflow? I do not have a Move Document action. It’s killing me that I cannot find a way to move a document from library A to library B while preserving the custom columns (even when they match from library to library)
  • vivek pandey
    Hello Anton,We want to move documents of Document Sets from one library to another library in sharepoint 2013 online(Office 365). We have already some workflow which are just doing entries in the new list and library but we are not able to move documents simultaneously from the Document Sets. So please suggest how we can archive required solution using these plumsail actions.
  • Maurizio Fidanza
    Hi Anton, will the document ID be preserved after the document move between folder or different document libraries? Regards Maurizio