Skip to content
Browse Power Automate tutorials

SharePoint has triggers for a selected item and a selected file, but none for several selected items. To process many rows, you can add a Batch column that people use to mark rows. A flow then finds the marked rows, generates the documents, and clears the marks.

This walkthrough creates both a Word document and a PDF for each row. Most people will need only one, so skip the parts you do not need.

Before you begin

You need:

The site, list, library and flow names in the screenshots are examples. Use your own.

As written, this flow supports one run at a time, whoever starts it and however it’s started, up to 50 marked rows in a run, and a list of up to 5,000 items. Nothing in the flow enforces the one run at a time; step 12 explains what happens if two runs overlap. It stops without making anything if more than 50 rows are marked. Step 4 explains why, and what to change for a larger list.

1. Create the Word template

The template is built the same way as for a single item. See Build the Word template for the full steps. In short:

  1. In Word desktop, lay out the headings and fixed text, then use the Developer tab to add a Plain Text Content Control wherever a value should go.
  2. In each control’s Properties, set Title to the name of the matching SharePoint column. Every control needs a different Title. The same value in Tag is optional. For a value that can run to several paragraphs, also select Allow carriage returns (multiple paragraphs).
  3. Use Design Mode to check your spacing, then turn it off.
  4. Save the file as a .docx and upload it to your template folder.

Content Control Properties dialog with Title and Tag set to Project Title

Use plain text controls. The connector doesn’t support rich text, building block gallery, date picker, or check box content controls, or legacy form controls. Input files can be up to 10 MB.

2. Add the Batch column

  1. In the list, select Add column > Yes/No, then Next.
  2. Name the column Batch.
  3. Set Default value to No.
  4. Select Save.

Create a column pane for Batch with type Yes/No and a Default value list

Batch is one shared column, not a private selection. Everyone who can edit the list sees the same marks, and a run processes every marked row, including rows that someone else marked. Before marking rows, check the column for marks you didn’t make. Separate batches for each person need a different design, which this tutorial doesn’t cover.

To use it, people select Edit in grid view, then mark the rows they want.

3. Start the flow

Build the flow in the default environment. The list’s flow menu only lists flows from there for this trigger.

  1. In Power Automate, select the default environment, and create a new flow.
  2. Add the SharePoint trigger For a selected item.
  3. Select your site and list.
  4. Name the flow, such as SharePoint Multi-Select to Document, and save it as you go.

For a selected item trigger with Site Address and List Name

The selected item only starts the flow. The flow works on rows with Batch set to Yes, whichever row you select. You could use a manual or scheduled trigger instead. A separate article covers starting it from a button on a page.

4. Find the marked rows

  1. Add the SharePoint action Get items, and select your site and list.
  2. In Filter Query, filter on Batch equal to 1. In OData form, this is:
Batch eq 1

Yes/No columns are stored as 1 and 0, so 1 means Yes.

Get items action with a Batch Equals filter under Filter Query

A filter decides which rows match. It doesn’t decide how many come back. If you only set the site and list, Get items returns 100 items, so a larger batch would be cut short. This flow sets its own limit of 50 rows, and checks for more before it makes anything. Each row makes two calls to the Word connector, which allows 100 calls per connection every 60 seconds, so keep batches modest. You can choose another limit, but try a full batch of that size before you rely on it.

  1. In the action’s advanced parameters, set Top Count to 51, one more than the limit. Leave Pagination off in the action’s Settings.

  2. After Get items, add a Condition. In the first box, enter this expression, choose is greater than, and enter 50 in the last box:

    length(body('Get_items')?['value'])

    The name in body() is the action’s name with underscores in place of spaces. If you renamed Get items, change it here.

  3. Under True, add Terminate. Set Status to Failed, Code to TooManyMarkedRows, and Message to More than 50 rows are marked. Clear some marks and run the flow again. Leave False empty.

Terminate stops the run and skips the remaining actions. Because the check comes before the loop, a batch that’s too large stops before any document is made, and every mark stays in place. Terminate can’t go inside a loop, which is another reason it sits here.

Asking for 51 rows proves only that no more than 50 came back. It doesn’t prove that every marked row came back, because on a large list Get items can miss rows (see the large-list note below). Step 12 explains what the list shows after a run.

If the list has more than 5,000 items, index the Batch column, and turn on Pagination. Microsoft lists a known limitation: on a list with more than 5,000 items, a filtered Get items may return no records if no items in the first 5,000 match the filter. The fix it gives is to enable Pagination. Set its Threshold to 51. Pagination works in pages, so it can return more than the threshold. As long as more than 50 rows come back, the check still stops the run. Microsoft doesn’t say that indexing or pagination returns every marked row. The view filtered to Batch = Yes depends on the index too: a view that shows more than 5,000 items can reach the list view threshold, and a view that can’t use an index may show only part of the list, or nothing. Try the flow and the view on a full-size copy of your list before you rely on them.

5. Prepare a run folder and a variable

  1. Add the SharePoint action Create new folder, after the Condition and outside it. Select your site, set List or Library to your working library, and set Folder Path to Runs/ followed by this expression:

    workflow()?['run']?['name']

    workflow() returns details of the current run, including the run’s name, so every run gets its own folder for working files.

Skip the rest of this step if your list has no multi-select columns.

The example’s Impact Areas column can hold several values, so they need to be joined into one piece of text.

  1. Add Initialize variable.
  2. Set Name to varImpactAreas and Type to String.

This action must stay outside the loop you add next, and outside the Condition. Keep concurrency control off on the loop, because each row uses the same variable.

6. Loop through the rows

  1. Add Apply to each, and set its output to body/value from Get items, the list of rows. Rename it Apply to each (Item Processing).
  2. Inside it, add Set variable for varImpactAreas, and set Value to this expression, which returns empty text. Rename it Set variable (Reset Impact Areas). This clears the value from the previous row.
string('')

Two apostrophes on their own also mean empty text, but the designer then shows Value as empty and won’t save the flow again.

Set variable (Reset Impact Areas) inside Apply to each (Item Processing), with varImpactAreas and the string('') value

  1. Still inside the outer loop, add another Apply to each. Set its output to Impact Areas from Get items, the list of values, and rename it Apply to each (Impact Areas).
  2. Inside it, add Append to string variable, and select varImpactAreas.
  3. In Value, search for your column and select Impact Areas Value, then type a comma and a space.

Add the inner loop first. If you add Append to string variable directly in the outer loop and select Impact Areas Value, the designer can wrap it in two new loops, one of them over every row, which repeats each row’s values once for every marked row.

Inner Apply to each on Impact Areas with Append to string variable

This pattern leaves a comma and space after the last value. Keep that in mind if the text needs to be exact.

The remaining actions go inside the outer loop and after the inner loop.

7. Fill in the Word template

  1. Add the Word Online (Business) action Populate a Microsoft Word template.
  2. Select your site, your template library, and the template file. The action then lists your content controls.
  3. Fill in each control with the matching column from Get items:
    • For Choice columns, select the entry ending in Value.
    • For a multi-select column, select varImpactAreas.
    • For a Person column, pick the part you want, such as Created By DisplayName.

Populate a Microsoft Word template fields with column tokens and the varImpactAreas variable

8. Save the Word document

  1. Add the SharePoint action Create file, and rename it Create file (Word Document).
  2. Set Folder Path to the run folder: your working library, then /Runs/, then the run-name expression from step 5. In the example, that is /Template Processing/Runs/ followed by the expression.
  3. Set File Name to Request-, then ID from Get items, then .docx.
  4. Set File Content to Microsoft Word document from the template action.

Create file action with a name built from Title, ID, and Approval Status, ending in .docx

The example in the screenshot builds the name from the title, ID, and status. Use the run folder and the Request- name instead. Named from the ID alone, each item ends at the same Word file and PDF on every run, even after someone edits its title, and the title appears inside the document. If you’d rather keep a history, see File names and repeat runs for what each naming choice keeps.

9. Convert it to PDF

Convert Word Document to PDF doesn’t support files labeled Confidential or Highly Confidential. Handle those files outside this flow.

  1. Add the SharePoint action Get file properties. Select the site and library, then set Id to ItemId from Create file (Word Document).

    Get file properties action with ItemId in the Id box

  2. Add Convert Word Document to PDF, and select your site and library.

  3. In File, type /Runs/, add the run-name expression, and type /. Then select File name with extension from Get file properties. The path starts inside the library, so leave out the library’s name.

10. Save the PDF

  1. Add another SharePoint Create file, and rename it Create file (PDF Document).
  2. Use the same run folder and the same name, ending in .pdf.
  3. Set File Content to the output of Convert Word Document to PDF.

Create file (PDF Document) with the run folder path, a Request- ID .pdf name, and the converted PDF as content

11. Move both files to the final folder

  1. Add the SharePoint action Move file, and rename it Move file (Microsoft Word).
  2. Select your site in Current Site Address, and set File to Move to the ID from Create file (Word Document).
  3. Select the destination site and folder.
  4. Set If another file is already there to Replace.
  5. Repeat for Move file (PDF Document), using the ID from Create file (PDF Document).

Move file options with Replace highlighted

A moved file keeps its name, so the final files are Request-<ID>.docx and Request-<ID>.pdf. The run’s folder is left empty. Step 12 covers what happens to it.

12. Clear the Batch mark

  1. Still inside the outer loop, add the SharePoint action Update item.
  2. Select your site and list.
  3. Set Id to the ID from Get items. If the list’s title column is required, as it is by default, also set it from Get items. The example’s is Project Title, set to Title.
  4. Set Batch to No.

Check every other field before saving. The action can show values for columns that you did not choose. In the example, Yes/No columns such as Change Management Needed also show No, and Choice columns with a default value, such as Approval Status, show that default. If a field holds a value in this action, the flow may write it to the row. Map those columns to their current values from Get items so that the update changes only Batch. Those values are the ones Get items returned when the run started, so don’t edit marked rows until the run finishes.

Update item action with Batch set to No, and another Yes/No column also showing No

Updating an item also changes its Modified details, and it can start other flows that watch the list.

  1. After the outer loop, and outside it, add a Compose action named Rows retrieved. Set Inputs to this expression:

    length(body('Get_items')?['value'])

    The run history then shows how many rows Get items returned. If a row’s actions fail, Rows retrieved is skipped; open Get items in that run instead.

The run’s empty folder stays in Runs. If a row’s actions fail, the run’s folder keeps any of that row’s working files that weren’t moved out, so you can see how far it got. The folder is named with the run’s name, which workflow() returns, so you can match it to the run in the run history.

Delete old run folders by hand. From time to time, open Runs in your working library and delete old folders. Before you delete one, make sure no run is in progress, and that the final documents for its rows are in the destination folder and open correctly. Keep a failed run’s folder until you’ve found out why it failed. Delete only folders inside Runs, never Runs itself or the destination folder.

Reading the list after a run. Update item keeps its default run-after setting, so it clears a row’s mark only after that row’s documents are made. A row whose actions fail keeps its mark.

A cleared mark means a run processed that row. A row still marked after a run wasn’t processed by that run. Its actions failed, or the run stopped before reaching it. It may have been marked after the run started, in which case it waits for the next run. Or Get items didn’t return it, as the large-list note in step 4 describes.

An empty view filtered to Batch = Yes shows only that no marked row is waiting. It doesn’t show that every row someone meant to include was marked, or that a row someone unmarked by hand was processed. If a run retrieves no rows while that view still shows marked rows, Get items didn’t return them. That can happen on a list with more than 5,000 items, as Microsoft describes.

One run at a time. Each row’s mark is cleared only after its documents are made, so a second run started before the first one finishes can pick up the same rows. That includes a run someone else starts, and a run started another way, such as from a button on a page. Nothing in the flow prevents it. Separate run folders keep the two runs from sharing a working file, but both replace the same Request-<ID> files, and each Move file replaces its file on its own:

  • Both runs can succeed without an error. Each final file shows the run that last replaced it. When two runs process the same row, its Word file can come from one run and its PDF from the other, and the row may have changed in between.
  • If a row’s actions fail after its Word file is moved and before its PDF is, that row’s Word file is new and its PDF is from an earlier run, or missing if there was none. The row keeps its mark.

So agree with everyone who uses the flow that only one run happens at a time. Don’t edit marked rows during a run either, because Update item writes back the values Get items returned when the run started, so an edit made in between can be overwritten. After a run that failed or overlapped another, open both final files for each affected row and check that they match the row and each other. To repair them, wait until no run is in progress, mark those rows, and run the flow once more. If that run succeeds, both files for each row come from it.

13. Test the flow

  1. In the list, select Edit in grid view, and mark two rows in Batch.
  2. Exit grid view, then select any one row. The flow is not offered if more than one row is selected.
  3. Select Integrate > Flows, and choose your flow. The first time, select Continue. Then select Run flow.
  4. Open the destination folder. Four files should appear. In the example, this takes a minute or two.

Project Requests folder with Request-1 and Request-2, each as a Word file and a PDF

  1. Open a file from each pair and check every value.
  2. Return to the list and confirm that Batch is cleared. After a run that succeeds, Rows retrieved in the run history should match the number you marked in this test. A cleared mark, not the count, shows that a row was processed. In Runs, the run’s folder is still there, and empty.
  3. Run it again with the same rows marked, and confirm that the files are replaced, not duplicated.
  4. Mark more than 50 rows and run it. The run should fail with your message, make no files, and leave every mark in place.

Troubleshooting

SymptomLikely causeWhat to do
The flow processes nothingNo rows are marked, or the filter is wrongMark rows, and use Batch eq 1
The run fails with your “more than 50 rows” messageToo many rows are markedClear some marks, run the flow, then mark and run the rest
Rows stay marked after a run that succeededThey were marked after the run started, or the list has more than 5,000 items and Get items didn’t return themRun the flow again. For a large list, follow the large-list advice in step 4
Create file failsFolder Path doesn’t match the folder that Create new folder madeUse /Runs/ and the same run-name expression in both
Empty folders build up in RunsEach run leaves its folder behindDelete old folders by hand, as described in step 12
A row’s Word file and PDF show different valuesTwo runs processed the row, or its actions failed between the two Move file actionsWait until no run is in progress, mark the row, run the flow once more, and check both files
The flow is not under Integrate > FlowsMore than one row is selected, the flow is in another environment, or it’s turned offSelect one row, build in the default environment, and turn the flow on
A control is missing from the template actionThe control is an unsupported type or has no titleUse a plain text control with a Title
Values from one row appear on the nextThe reset step is missingAdd the Set variable step at the start of the outer loop
Multi-select values show as JSON textThe wrong token was usedUse the value token in the inner loop, with Impact Areas as the loop’s input
Other Yes/No columns changed after the runUpdate item wrote its default valuesMap those fields to the current row values
Rows are processed againUpdate item failed, so Batch stayed YesCheck run history, and confirm Update item is inside the outer loop
Convert to PDF cannot find the fileThe file value doesn’t hold the run folder’s pathUse /Runs/, the run-name expression, /, and File name with extension
A step after Create file cannot find the new file, although the path is rightThe file is not available yetMicrosoft recommends a short delay, about a minute, before later actions use a file created from the Word connector. Add a Delay before the step that fails
The conversion fails for a labeled fileThe file has a Confidential or Highly Confidential sensitivity labelHandle these files outside the flow
Documents are missing formattingTemplate spacing or layout issueAdjust the Word file and upload it again

Next steps

Instead of the list’s flow menu, you can start this flow from a single button on a SharePoint page. Copy the flow and change its trigger to Power Apps (V2). The canvas app rule in Licensing then applies. The separate article on running a flow on multiple items from a Power App button shows how.

Companion video

Video: Batch Generate Word & PDF from SharePoint List with Power Automate (Step-by-Step). The video creates the files at the top of the template library, named from the title, ID, and status, before moving them, and has no limit on marked rows. The steps here use a folder for each run, name the files by ID only, and stop when more than 50 rows are marked.

If the player is blocked on your network, open the video on YouTube.

Need help applying this to your own setup? Read about consulting.