Using Power Automate and Excel (or any other available data source 😉), you can bulk import tasks into planner using Power Automate. I have previously recorded a video on this process and use both a tasks table and a config table to support this cloud flow. This will enable you to dynamically choose the group and plan name, as well as import planner tasks involving a title, bucket id / name, start and due date, assigned user ids, a category, priority, check list and file attachment(s)! This flow is not for the faint hearted but should support you with your goal to build a Planner Power Automate integration.
A sample flow and template file is available to download from my github in the video description and at the bottom of this article, but I would strongly encourage you to watch the video to see how I created this solution.
As some of the expressions are complex, I have made them available via this post to suppliment the original video.
The Trigger and Initial Setup
The flow is currently manually triggered, you could of course create an excel file and run on a recurrence trigger or use when a file is created and simply upload a template file to a watched document library. Based on the requirement to import my solution (legacy) there are some short notes to follow and you will need to update the first two list rows actions which retrieve the tasks and config table from Excel.
Getting the Group ID
In order to run this solution dynamically, we need to retrieve the group id of the plan. You will tend to see that I use scopes to bring actions with a particular purpose together. We list the teams that we have access to, filter that teams list where the team name is equal to the name from our config table and then output the group id into a compose.
The expressions used here are:
outputs('ListRowsTableConfig')?['body/value']?[0]?['GroupName']
body('Filter_array_Teams')?[0]?['id']
Note that we have used the integer value [0] to retrieve the first object from the array, otherwise we would find ourselves in an apply to each loop. The alternative is to use first().
Listing Plans and Buckets
Below we list all of the plans for an existing group and then filter those plans based on the plan name from the excel config table. Finally we list all buckets that exist on that plan.
The expressions used here are:
outputs('ListRowsTableConfig')?['body/value']?[0]?['PlanName']
body('Filter_array_Plan_ID')?[0]?['Id']
Create Buckets that are missing
Next we must create bukets that are missing from the action above. For example, we have a plan with 3 buckets but our excel table has 4 buckets, maybe we have introduced a new quarter (Q4) or project stage to our table but not yet configured it on our plan. The next few actions will identify the missing buckets and create them for us.
The first select (in text mode) allows us to create an array of bucket id’s (note that we use the name and not the guid) used in our excel sheet (as seen above) and then using a union, we can get the distinct bucket id’s (i.e. names). We can then use another select to get the bucket names from the list buckets pre creation action and then filter from the unique buckets (distinct buckets on excel), where the buckets from the planner does not contain the name of the bucket from distinct buckets. The expression used here is item(), to refer to each bucket id / name.
Then, for each bucket identified by the filter, we loop and create those buckets. The input to the apply to each is the output from the filter array, the name is based on current item, group id based on the compose of the group id and plan id based on the plan id from the filter.
Expressions used here are:
body('Filter_array_Plan_ID')?[0]?['Id']
List buckets post creation and create an Object {} of Buckets
We then list the buckets again post creation in order to get the internal bucket id’s as used to create the tasks in the final stages of our flow. These actions rely on the unique internal guid and not the friendly name you might call your bucket. As the buckets are returned as an array, we have repurposed this data to create an object. The advantage of an object is that you can call the guids by the friendly name. I have seen other solutions require that you store the guid in the table, this is not the case here. If you want to understand more about objects, watch this video https://youtu.be/PD980sKKx0E.
The select, in text mode, allows us to create an array of strings based on a key/value pair –
"Bucket Name" : "Bucket Guid"
We can then use this array of strings to our advantage, join them on a comma, add a { and } to the start and end and then parse as JSON. All of which you can watch in my video above. The alternative is to filter for each bucket guid as you create your tasks or store that guid in your sheet. I think this method is easier once setup and will create something similar to:
{
"Bucket Name1" : "Bucket Guid1",
"Bucket Name2" : "Bucket Guid2"
}
Expressions used here are:
concat ('"', Item()?['Name'] , '":"', item()?['id'], '"')
json (concat ('{', join(body('SelectBuckets'), ','), '}'))
Create tasks on our Plan
For each row in our excel table, we want to create a new task in our planner. For this we have a scope, with 7 actions! The first action, will create a simple task, with the bucket id, start and due date, assigned user ids, category and don’t forget your priority (not in screenshot but hidden away at the bottom of the action parameters).
Expressions used here are:
Plan ID: First(body('Filter_array_Plan_ID'))?['id']
Bucket ID: outputs('ComposeBucketsArray')?[items('Apply_to_each')?['Bucket Id']]
Due Date: If(empty(items('Apply_to_each')?['Due Date Time']),formatDateTime(Adddays(items('Apply_to_each')?['Start Date Time'],7),'yyyy-MM-dd'),items('Apply_to_each')?['Due Date Time'])
Pink, Red, Yellow etc: If(equals(items('Apply_to_each')?['Category'],'Pink'),true,false)
Creating a Check List
Next we must create an array for our check list and each item in the list must have a unique ID, a title (based on our excel table column) and an ischecked value, for which we have set to false, i.e. not checked. For that we use a select and a filter (to remove any objects with a blank title).
Expressions used here are:
From: range(0,length(split(items('Apply_to_each')?['Check List'],',')))
id: item()
title: split(items('Apply_to_each')?['Check List'],',')?[item()]
To explain in a bit more detail, the range creates an array of numbers from 0 based on the length of an array. In the excel table there is a task list that is comma seperated. Split will create an array of tasks and length will count those values. This is our unique ID.
In the Map, we have id, which is item() and that refers to the unique ID from the range i.e. [0,1,2]. The title is based on the integer index of an array, based on the split of the comma seperated list. Therefore if you have 3 check list items, an array [item1,item2,item3] is created. To select item2, we use index [1], item3 is index [2]. Indexes start from [0], i.e. first(). Range allows us to create both a unique ID and select list items by integer.
The filter array simply removes any values from the array where the title length is null length.
Creating an attachments array
The attachments array is based on SharePoint links to a file(s), comma seperated. As before we use a select and a filter array to remove any objects where the resourcelink is blank. The alias is fixed, resource link is a link to said file and is accessed based on integer index (same as above) and type is based on word or excel and a check is done on the file extension.
Expressions used here are:
From: range(0,length(split(items('Apply_to_each')?['File Attachment'],','))) ResourceLink: split(items('Apply_to_each')?['File Attachment'],',')?[item()] type: If(endsWith(split(items('Apply_to_each')?['File Attachment'],',')?[item()],'lsx'),'E','W')
Update the Task with attachments, check list and make the check list visible
Lastly we can add the references i.e. the links and the check list from both of the respective filter array action outputs. This is achieved with the update task details action. If you also want the check list items to be visible, you can enable this with a call to the Graph API based on the following expressions:
URI: https://graph.microsoft.com/v1.0/planner/tasks/@{outputs('Update_task_details')?['body/id']}/details
Body: { "previewType": "checklist" }
Content-Type: application/json
CustomHeader1: If-Match: @{outputs('Update_task_details')?['body']?['@odata.etag']}
CustomHeader2: Prefer: return=representation
The complete apply to each excel row to create and update a task looks like follows:
The sample excel template and template flow (legacy) can be downloaded from GitHub. Please let me know how you have developed your own solution in the comments below or via Social Media via DamoBird365.
Hello Damian,
I’m struggeling with the automatic creation of ‘apply to each” when I create all the steps in “ScopeCreateBuckets”. How can I prevent this?
Hi Andrea, what errors or problems are you encountering? You would need to use expressions. Are you selecting dynamic content and creating an apply to each? I’ve just done a video on why apply to each occurs – Power Automate | Apply to Each | Why? | Arrays and Objects
https://youtu.be/d99Rr5djcME
Hi Damian,
I’m also struggling here. The issue is when creating the Filter Array step within ‘ScopeCreateBuckets’ it is automatically putting it inside a “apply to each”, but in your demo that isn’t the case. Also, in the Filter Array step it is configured as From Outputs (ComposeUniqueBuckets), Output (selectBucketsFromPlanner) does not contain “Item”. Can you clarify where the “Item” is coming from? in the video you never hover over it so it isn’t clear.
Hi Damian, Thanks for this, its really helpful! I have used the legacy template you made but I am hitting errors on a couple of steps. I get the error: The ‘inputs.parameters’ of workflow operation ‘List_plans_for_a_group’ of type ‘OpenApiConnection’ is not valid. Error details: The resolved string values for the following parameters are invalid, they may not be null or empty: ‘groupId’ , for lists plan for a group, list buckets pre creation and list buckets post creation. Please could you help trouble shoot this? Thanks
I have the same problem
Hey Damian thanks a lot for this. I have a question: I am getting the following error on the HTTP Request:
The If-Match header must be specified for this kind of request
Can you expand on that portion of the code? How do I go about getting past this error?
Hey Damian! Thank you SO much for sharing this solution. What a blessing! I’ve been able to modify the flow for my purposes and it works great. There’s just one thing that I’d like to know if it’s possible to do. Is there a way to define the order that the tasks are created in so they’ll display in the order I want in the buckets? I’ve read some Microsoft Learn articles about OrderHint and the Get PlannerBucketTaskBoardTaskFormat method but I don’t know how to add that to the existing flow.
I’ve not investigated the ordering of tasks. Presumably they don’t insert in the order you create them? Is it based on name or can you see a pattern?
Correct, they don’t insert in the order I have them listed in the table and I don’t see a discernable pattern in how they’re being inserted. In a previous version of the flow, I noticed that if I wanted them listed in the bucket in a particular order, like numerical from top to bottom, then I had to list them in descending order in the table. This way, the task with the lowest numerical value was created last and was therefore listed first in the bucket. Once the flow became more complicated, that stopped working, even though they’re still listed in the same order in the table.
Damian,
Do you have any thoughts on how I might be able to resolve the task order issue?
It’s not something I have had time to investigate, I would suggest you try the sort() expression on your array of tasks, albeit it sounds like order doesn’t help here. Next, do you have concurrency turned on via an apply to each, this would potentially cause the tasks to be created in a random order.
Hallo Damien,
Many thanks for the instructive video and post. I would like to ask if there is a simpler solution for the buckets when they are predetermined and already exist in the plan. Can I not just find the actual bucket name from the ID and match the name to the bucket name in my Excel file?
Note: I start with “For a selected row’ rather than Manually trigger a flow and ListRows….
Thanks,
Vinny
Absolutely, if you can get the ID yourself, you could include that in your excel sheet. I am glad the video / post has otherwise been of help. Are there any other Planner automations that you wish exist?
Hallo Damien,
Thank you for the idea. I have found the corresponding Bucket ID to each Bucket Name and used an XLOOKUP in my Excel table to populate the relevant cell on my import table. The Create A Task now uses that ID.
Maybe there is a way to do that directly in the flow but this works for now.
I only have one last issue. I receive the due date as dd/MM/yyyy but it seems the flow only accepts the date in the format MM/dd/yyyy. I have tried the formatDateTime function to convert but just cannot get it to work. It always tells me “…’formatDateTime’ expects its first parameter to be of type string. The provided value is of type ‘Null’….” do you have a hint how this works?
As far as other planner, I also used your Export Planner Tasks to Excel automation. I am just new to both Planner and Power Automate so I am sure more things will come up in time.
Danke!
I would check your expression. If the value is of type null, it means that nothing is being passed to your formatdatetime expression. I’ve a video on dates too btw 😉
Okay, thanks for the tip. I will look for the video!
Hi Damien,
i’m trying to import your flow, but i always get an error:
Fehler beim Speichern des Flows. Code: MultipleErrorsOccurred, Meldung: “The dynamic operation request to API ‘excelonlinebusiness’ operation ‘GetTable’ failed with status code ‘NotFound’. This may indicate invalid input parameters. Error response: { “status”: 404, “message”: “Item not found\r\nclientRequestId: d5457d1d-beb7-4759-a8c4-7d532f3ff2d9\r\nserviceRequestId: be48e35f-6743-44d8-89b4-4066738390c6”, “error”: { “message”: “Item not found” }, “source”: “excelonline-ne.azconn-ne-003.p.azurewebsites.net” };The dynamic operation request to API ‘excelonlinebusiness’ operation ‘GetTable’ failed with status code ‘NotFound’. This may indicate invalid input parameters. Error response: { “status”: 404, “message”: “Item not found\r\nclientRequestId: d5457d1d-beb7-4759-a8c4-7d532f3ff2d9”, “error”: { “message”: “Item not found” }, “source”: “excelonline-ne.azconn-ne-003.p.azurewebsites.net” }”
I tried it with createing a new flow and updating an existing one… Can you help with this?
I am not familiar with the error but wonder if you need to ensure you have the correct table names in your excel file? Click on the table in excel and then the table tab.
Hi Damien,
actually, I got the same error here. I checked all steps as explained in your video tutorial and also the “excelonlinebusiness” connection which I had to create just for this certain flow to be able to import it.
Do you maybe have any advice on how to proceed?
Thank you!
Hi there, first of all, thank you so much for this tutorial! I am also getting this same exact error message during the import process. I also made sure my Excel Online (Business) connection was up to date. I hadn’t matched up the table names with my Excel file yet, but I assumed I could do that once the flow was imported. Any input would be greatly appreciated!
It’s a strange one Natalie, I’m not sure, where are you based? Wondering if there is a curious difference between geographies as there are folk that use this. Drop me an email on damien@damobird365.com and I will try to help.
I am interested if there is a solution as well because I am also getting the same error message. I am hopeful that there is a solution to this problem because I think this will be a great tool for importing my tasks. Wondering if this is a version issue as I noticed some differences in the import menu when I start the import. Please email if more information is needed.
I was able to solve my issue of loading the flow by disabling my companies VPN. Once this was disabled, the Import worked just fine.
Thank you for sharing this Fran! It will inevitably help others too. 👍
When I click in the Priority box in Create a task Preview, Priority is not listed as an option in dynamic content.
I want to let you know that turning off concurrency on the apply to each solved my problem. I truly appreciate your help. Thank you!
Brilliant Kirsty, thanks for reporting back 👍 and enjoy your tasks in strict order 😉
Hi Damien,
I recreated your flow manually to try to better understand the flow etc.
I initially had a problem with permissions when attempting to use the original method for listing plans for a groupid. I have found I can get past that by selecting the group from a list presented when I select the drop down.
My larger problem is now the flow runs and has created the buckets in task by planner however it falls over at the CreatingTasks step with the following error –
InvalidTemplate. Unable to process template language expressions in action ‘Create_a_task’ inputs at line ‘0’ and column ‘0’: ‘The template language expression ‘outputs(‘ComposeBucketsArray’)?[items(‘Apply_to_each’)?[‘Bucket Id’]]’ cannot be evaluated because property ” cannot be selected. Please see https://aka.ms/logicexpressions for usage details.’.”
Any help appreciated
Cheers
Hi Alex, good to hear of your progress. I guess that you are maybe missing an _ in the name of your field? The error would suggest that items(‘Apply_to_each’)?[‘Bucket Id’] is returning null. If you can check back on the flow history, you will hopefully see the field for bucket id and it will possibly be bucket_id or maybe even bucketid ? Ultimately you want to look at the input to the apply to each to ensure that you have a bucket id. Let me know what you find.
Hi Damian,
Thanks after some sluething realised that I had used Bucket Name in teh excel sheet as the field you called Bucket_Id, it didn’t like the space I think so I renamed the filed Bucket_Id and it worked.
Hi Damien,
Are you able to provide direction on an error we’re getting on importing the Bulk Import Tasks into Planner project? Power Automate is reporting on import:
The solution file is invalid. The compressed file must contain the following files at its root: solution.xml, customizations.xml, and [Content_Types].xml. Customization files exported from previous versions of Microsoft Dynamics 365 are not supported.
I didn’t see those files in the zip download. Are they available in another directory?
I’ve exported this as a legacy flow, rather than a solution. Please try import as a legacy/personal flow. 👍
Hi Damien, Disregard, We did the flow import (legacy) and now get a 404 error referencing the excelonlinebusiness API operation GetTable failing with status code ‘Not Found’
Hi! When I get to the create a task step, I keep getting this error and I’m not sure what is causing it.
Flow save failed with code ‘InvalidTemplate’ and message ‘The template validation failed: ‘The inputs of template action ‘Create_a_task’ at line ‘1 and column ‘9185’ is invalid. Action ‘Apply_to_each’ must be a parent ‘foreach’ scope of action ‘Create_a_task’ to be referenced by ‘repeatItems’ or ‘items’ functions.’.’.
Manually trigger a flow
Hi Damian,
I was wondering if you have ever tried to do this process with a SharePoint list instead of an excel file? I’m assuming it would be a similar process, but I am not sure how to modify this
I’ve briefly covered this in a video last week. It’s not that much different. Take a look here 👀 Import Planner Tasks into Dynamic Groups and Plans via Power Automate
https://youtu.be/EbmrOvAC8DM from 25:26
How easy would it be to add an import to the notes section of planner tasks as well?
I may just be going mad on this one. No matter what I seem to try it just doesn’t like the URI detail for the send HTTP request. I’ve tried V1(Office Orange Logo) & V2 (Blue round things logo)
I constantly get this error.
URI path is not a valid Graph endpoint, path is neither absolute nor relative or resource/object is not supported for this connector. Resources: me,users Objects: messages,mailFolders,events,calendar,calendars,outlook,inferenceClassification. Uri:
I’ve tried the URI as detailed in this on other articles,
https://graph.microsoft.com/v1.0/planner/tasks/@{outputs(‘Update_task_details’)?[‘body/id’]}/details
and tried substituting elements with the local URL of the planner but nothing is working for me.
Do I need to customise this bit?
https://graph.microsoft.com/v1.0/planner/tasks
I’ve tried using the URL from the planner, which woks to open the plan in my browser?
What is the difference between a URL & URI?
Please help
Hey, I am getting an error message ( IT LOOKS LIKE SOMETHING WENT WRONG: The provided flow name ‘draft_ac38bf38-a38e-4f37-ac70-174e86a6fcfd’ contains invalid characters.) when trying to import/save the flow.
Any ideas if I’m doing something wrong?
Hi and thanks for the very helpful video!
As mentioned before I get some errors by importing the zip file with the legacy package. Once I updated the connection, I get the error message ” Import failed for one more package resources.” as mentioned and click on ” Save as a new flow”. But then I have an error message saying: “The provided flow name ‘draft_ac38bf38-a38e-4f37-ac70-174e86a6fcfd’ contains invalid characters.” and I am not able to import the flow in my environment.
Any idea how could I solve it?
Thanks again for your content! 🙂
I am getting the same error message.
I am having the same issue as Pierre. ” Save as a new flow”. But then I have an error message saying: “The provided flow name ‘draft_ac38bf38-a38e-4f37-ac70-174e86a6fcfd’ contains invalid characters.” and I am not able to import the flow. is there a way to resolve this..
I am having the same errors as well, have you had any luck with a solution for this yet?
i uploaded and saved the file from GitHub but When i try importing solution to power automate i receive the error: The solution file is invalid. The compressed file must contain the following files at its root: solution.xml, customization.xml, and [Content_Types].xml. Customization files exported from previous versions of Microsoft Dynamics 365 are not supported
It will be a legacy import and not a solution import.
Hi and thank you for your video, it’s really helping me as a beginner.
I’ve tried to recreate your flow but altered to make it relevant to a work project, but it wasn’t working so I thought I’d go back to basics and recreate exactly what you did in your video.
I’ve gotten to the ComposeBucketsArray stage and added the json expression as written above:
json (concat (‘{‘, join(body(‘SelectBuckets’), ‘,’), ‘}’))
but when I test the flow at this stage, it is failing and returning the error “Action ‘ComposeBucketsArray’ failed” with the details:
Unable to process template language expressions in action ‘ComposeBucketsArray’ inputs at line ‘0’ and column ‘0’: ‘The template language function ‘json’ parameter is not valid. The provided value ‘{{“\”{\”Week 3\”:\”\”}\”:\”EFnqhkhrIUaen8S6jABoW5cAInrD\””:””},{“\”{\”Week 1\”:\”\”}\”:\”bSEQi6RmcUqVK44jloxb9ZcAGRqw\””:””},{“\”{\”Week 3\”:\”\”}\”:\”SAwNu9GzZU-tm7Hu1s86-5cANDUw\””:””},{“\”{\”Week 1\”:\”\”}\”:\”fbXS1pwbd064LDasQ0lPm5cAK0z_\””:””}}’ cannot be parsed: ‘Invalid property identifier character: {. Path ”, line 1, position 1.’. Please see https://aka.ms/logicexpressions#json for usage details.’.
Not quite sure where I’ve gone wrong, however I also noticed when I tested the flow previously after I’d added the actions under ‘ScopeCreateBuckets’ when I went to check the buckets had been added in Planner, they are appearing as {“Week 1″:””} and {“Week 3″:””} instead of Week 1 and Week 3. Could this be contributing to the issue?
It’s quite a while ago since I put this one out but what it is doing is generating an object with key/values week1:guid so that you can get the bucket guid directly. Otherwise you need to use filter array and it’s rather inefficient. You could watch an example of similar data transformation here https://www.youtube.com/watch?v=sVRT1-VY8uI&t=128s
Ji Jo E,
I have exactly the same problem.
Did you got a solution?
Thanks.
Hi, I have a planner task that I want to update the check list items by PA. In one bucket my task has 4 checklist items. The next buck I only need to have 3 checklist items. I have tried using the “update task details”, but I cannot get rid of the 4th checklist item. how can I delete the 4th check list item? Can I use http request to remove the additional check list item?
I need a template to load multiple/bulk – Tasks on Planner from an Excel sheet/list