It is possible to quickly split a workbook into multiple worksheets based on a key column using Office Scripts in Power Automate. For instance, if your Excel sheet contains data relating to sales and for each of those sales, the sales manager responsible is in a column, you can automatically detect the unique names, create sheets for each of them, and populate those sheets with the sales relevant to that manager. Furthermore, if you would rather unique workbooks for each of those distinct names, I’ve got a solution for that too and you could use the final script just to bulk load data into Excel efficiently, without using any add a row actions.
If you are new to Office Scripts, I would recommend you take a look at the Microsoft Documentation. Key things to note are that data sent to and from a script in Power Automate is limited to 5MB and the range of cells is limited to 5 million. A user can make 1600 api calls to Office Scripts per day. If you are familiar with the out of the box add a row to a table action, you will be aware how long it can take to load data into Excel. Office Scripts can perform bulk data loads, formatting, ordering, all from a single action. I’ve a few Office Scripts articles on my blog too and even more on my Office Scripts – YouTube playlist!
Sample Excel Workbooks
I headed over to Kaggle and picked up a couple datasets, the first had 400+ rows for the Top 10 Highest Grossing Films (1975-2018) and another with 100,000+ for Top 48 automakers daily stock prices 2010-2022. The former had a column for the main genre, of which there were 16 distinct values, the latter 48 (!) car manufacturer codes. Using this data I was able to test the reliability of my proof of concept.
The scripts
I have three scripts for this solution, albeit some of my inspiration and code came from Microsofts own sample solution for Combine workbooks into a single workbook. Running these from Power Automate is really straight forward using the single action, an example of which can be seen below:
The three scripts are as follows:
Split Workbook into Multiple Worksheets Based on Key Column
This has three input parameters as seen above, the key column name you want to split the workbook on, a table name (if one exists and / or to create if it doesn’t) and a default sheet name. The script has the ability to create a table commented out, a clever feature of Office Scripts if you are going to be receiving an excel file without a table created. Then it will retrieve the unique names from the column defined, loop through these creating a new sheet and filtering the data on the main sheet before copying the data into the new sheet for each loop. The only limitation I have seen here is that sheet names must be 30 characters or less. This script will run in a matter of seconds and result in an updated workbook with multiple sheets of data based on the unique key column name data. 17 sheets for the blockbuster example and 49 for the car manufacturer, remembering that the original worksheet will remain untouched.
function main(workbook: ExcelScript.Workbook, KeyColumn: string = "ManagerName", //Specify Key Column Name to Filter On MainTable: string = "Table1", //Either existing OR new table name SheetName: string = "Sheet1" //Default sheet name ) { // Get the worksheet by name const selectedSheet = workbook.getWorksheet(SheetName); // Alternatively, get the first worksheet (uncomment below and comment out above) // const selectedSheet = workbook.getFirstWorksheet(); // Create a table using the data range. let newTable = workbook.addTable(selectedSheet.getUsedRange(), true); //***Comment out if new table not required newTable.setName(MainTable); //***Comment out if new table not required //Define Table Name const TableName = workbook.getTable(MainTable); //Get all values for key column const keyColumnValues: string[] = TableName.getColumnByName(KeyColumn).getRangeBetweenHeaderAndTotal().getValues().map(value => value[0] as string); // Filter out repeated keys. This call to `filter` only returns the first instance of every unique element in the array. const uniqueKeys = keyColumnValues.filter((value, index, array) => array.indexOf(value) === index); console.log(uniqueKeys); // Filter the table to show only rows corresponding to each key and then for each filter uniqueKeys.forEach((key: string) => { TableName.getColumnByName(KeyColumn).getFilter() .applyValuesFilter([key]); // Get the visible view when a single filter is active. const rangeView = TableName.getRange().getVisibleView(); // Create a new sheet let sheet = workbook.addWorksheet(`${key}`); // Set the range of data from the filter let range = sheet.getRangeByIndexes(0, 0, rangeView.getRowCount(), rangeView.getColumnCount()); //Load Data into new Sheet based on selected range range.setValues(rangeView.getValues()); }); //Clear Filter TableName.getColumnByName(KeyColumn).getFilter().clear(); }
Split Workbook into Data Arrays based on Key Column
This starts off very similar to the script that creates multiple sheets, and again has the option to create a table if the sheet does not contain one. The main difference here is that rather than creating sheets, the filtered data is passed to an array as defined by worksheetInformation and is returned back to Power Automate via the Output. This allows the final script to be called with the output as input, and from this we can create multiple unique Workbooks with the unique data in the main default worksheet, sheet1.
function main(workbook: ExcelScript.Workbook, KeyColumn: string = "ManagerName", //Specify Key Column Name to Filter On MainTable: string = "Table1", //Either existing OR new table name SheetName: string = "Sheet1" //Default sheet name ) { /*Commented out if new table not required // Get the worksheet by name const selectedSheet = workbook.getWorksheet(SheetName); // Alternatively, get the first worksheet (uncomment below and comment out above) // const selectedSheet = workbook.getFirstWorksheet(); // Create a table using the data range. let newTable = workbook.addTable(selectedSheet.getUsedRange(), true); newTable.setName(MainTable); */ // Create an object to return the data for each workbook. let worksheetInformation: WorksheetData[] = []; //Define Table Name const TableName = workbook.getTable(MainTable); //Get all values for key column const keyColumnValues: string[] = TableName.getColumnByName(KeyColumn).getRangeBetweenHeaderAndTotal().getValues().map(value => value[0] as string); // Filter out repeated keys. This call to `filter` only returns the first instance of every unique element in the array. const uniqueKeys = keyColumnValues.filter((value, index, array) => array.indexOf(value) === index); console.log(uniqueKeys); // Filter the table to show only rows corresponding to each key and then for each filter uniqueKeys.forEach((key: string) => { TableName.getColumnByName(KeyColumn).getFilter().applyValuesFilter([`${key}`]); // Get the visible view when a single filter is active. const rangeView = TableName.getRange().getVisibleView(); // Get values from filter let values = rangeView.getValues() worksheetInformation.push({ name: `${key}`, data: values as string[][] }); }); //Clear Filter TableName.getColumnByName(KeyColumn).getFilter().clear(); return worksheetInformation } // An interface to pass the worksheet name and cell values through a flow. interface WorksheetData { name: string; data: string[][]; }
Create Worksheet based on Data Array
Using the output from the previous script, we can supply an array of worksheet information and with this, determine the number of columns and rows before adding to the default sheet of a new Excel File. We then perform some nice to have formatting, like autofitting columns and create a table, so that the data is now queryable via the native Excel actions. Albeit why would you use list rows when you have Office Scripts?
function main(workbook: ExcelScript.Workbook, MainTable: string = "Table1", //new table name worksheetInformation: WorksheetData) { // Get default worksheet Sheet1 let sheet = workbook.getWorksheet(`Sheet1`); // Create range based on the size of data let range = sheet.getRangeByIndexes(0, 0, worksheetInformation.data.length, worksheetInformation.data[0].length); //Populate sheet with data range.setValues(worksheetInformation.data) //Autofit column width range.getFormat().autofitColumns(); //Create New Table let newTable = workbook.addTable(range, true); newTable.setName(MainTable); } // An interface to pass the worksheet name and cell values through a flow. interface WorksheetData { data: string[][]; }
A sample Flow
The soltuion to split the workbook into multiple worksheets is all done in one action. Call the first script on the file of your choice and set the key column name, table name and sheet name. If you are looking to perform a split into multiple files, you need to combine the second and third script on an apply to each. I use a compose with the file content of an empty Excel for this and can then create a new file easily. Split the workbook into an array of data sets and then loop through them all to create new files and populate with data using the third script. Note that I inserted a delay of 3 seconds between the create file and run script. Excel can be a bit touchy when it comes to running scripts. Generally scripts will run but if you try to run them in parallel or access the same file continuously, you might get timeouts and retries.
Bulk load data to Excel Using Office Scripts
As another nice bonus, this final script can be used to bulk load data to Excel in a single action, as long as the data size is not greater than the 5MB limit. Potential data sources could be an API, Dataverse or Microsoft List datasets. Compose an array with an array of headers, followed by an array of data per row and you can pass it straight into a new Excel file using the technique above and the third script. A sample array from a Microsoft List can be seen below:
If you were looking for a method to create such an array structure, don’t go jumping on an apply to each loop, try something a bit more efficient like a compose (for the header), a select, and a final compose and a union as follows:
You can then pass the array to a newly created Excel File and this data will be populated in the new file almost immediately! You can see a similar method I have demonstrated here.
Office Scripts are a great method of extending Excel integration with Power Automate. The recording tool is a great way of learning what is possible and building sample code and the examples from the Microsoft Team are also incredibly useful for a newbie. I hope that the above article has provided you with enough information to try this yourself. Please let me know below how this has helped you and don’t forget to watch my video demo too.
hi, i have tried the first script i.e. Split Workbook into Multiple Worksheets Based on Key Column. and my key column is in number format. when i try to run the script, there is error at step no 29 as follows : Line 29: Filter applyValuesFilter: The argument is invalid or missing or has an incorrect format.
do you know why?
Hi Bella, try updating the script as follows: TableName.getColumnByName(KeyColumn).getFilter().applyValuesFilter([key.toString()]);
I believe this is because a number is treated as a number and it needs to be a string to search on.
This is an incredible piece of work, thanks so much. Even with my limited flow knowledge I was able to replicate it. I also combined it with your other flow to then create separate workbooks of each worksheet in OneDrive so thanks again!
I’ve also tried to save those workbooks to custom onedrive folders based on the name of the created worksheet, following your other article on saving attachments but my array knowledge is not sufficient so the flow fails.
Any change to write a follow article on that? Any feedback would be much appreciated.
Thanks again for your great work!
Drop me a message via contact me on my blog and I will see if I can help.
Thank you, this is really helpful! Well explained and I actually implemented this in one of our automation projects and it worked well.
I do have one issue. When the new workbooks are created, There is a column with dates that should be a date format but on the new split workbooks, it turned to the numeric version. Any suggestions how we can remedy this? Thank you.
Hi Ron, I have the same issue with the date format. Did you manage to resolve this? Thanks Phil
// format date
sheet.getRange(“D:D”).setNumberFormatLocal(“dd/mm/yy;@”);
seems to work added after create a new sheet.
Hello – This was awesome and very easy to follow! Thank you for this. One question I have for you involves a file with a template structure. For example:
Let’s say I have a table that starts on A2. On the first row (A1) I have some instructions on what each header means and some notes for the end users. Is there any way to keep the formatting of the file, whether I have locked cells, notes, information on the top row, etc. available in all the files that are split?
I’m able to do it with a VBA code (I’m not an expert, just something I found online and tweaker), that essentially allows me to name a range but it keeps the structure exactly the same.
I was having a bunch of issues setting this up but all of them were user error. I finally fixed all of those but I cannot get past this error:
We were unable to run the script. Please try again.
Office JS error: Line 18: Workbook addTable: Some header row values have more than 255 characters and will be truncated. Do you want to continue?
None of my headers (or even fields) have more than 30 characters, let alone 255, and I can’t figure out what is wrong!
Try running the script in excel and output the sheets array to console.log(). It might help identify what’s up.
When I run that last script in Excel I get:
Line 9: Cannot read properties of undefined (reading ‘data’)
Is your sheet called sheet1? Do you have a table already created or is it a basic worksheet.
Sir Even i am facing this issue. In my data one of the columns has data more than 255 character. could you please resolve these issues.
Hi, did you manage to resolve this?
I resolved this – on the run script action you need to click the table icon to ‘switch to input entire array’
Hi – I was wondering if there was a way to do this without changing the formatting. Some of the cells I have are color coated and when splitting to a data array I lose this. Any advice?
Hey Molly, I am not sure to be honest. I’ve looked over https://docs.microsoft.com/en-us/office/dev/scripts/overview/excel and there is no obvious example. You could try this a different way and create a copy of the file for each workbook and then filter/delete the data on each copy?
Where do I get the script for “Split Workbook into Multiple Worksheets Based on Key Column”?
It’s all in the blog post?
Hi. I created a flow according to your video and I faced a problem with the script, where worksheets are created based on array: “Cannot read property ‘getRangeByIndexes’ of undefined
clientRequestId”. What can be the reason for that? I’d apprreciate your answer very much.
Thank you for the script creating a new sheet for a specified column item. Great.
Hi, Thank you for wonderful scripts (Saved my day). The script .Split Workbook into Data Arrays based on Key Column’ & ‘Create Worksheet based on Data Array’ along with flow works fine with my login. However I have shaed the flow with other user getting an error ‘Script not found. It may have been unshared or deleted.’ on Run Script step.
I have tried to sharing script from my oneedrive, also shared on script on file but no luck.
Can you please help
Hiya,
You’re tutorials and script are amazing and i’m certainly learning a lot from them especially how you actually go into providing information on the various steps.
I saw your other tutorial about splitting worksheets and then deleting work sheets via power automate. I am having an issue where I attempt to add a dynamic value to the deleteworksheet script on the flow but it only shows me ‘Item’ from the filter array and then even if i added that it creates a new apply to each loop as opposed to remaining in the same apply to each nor does it show me the body dynamic value of filter array.
Hi Evan, I have replied to your post on the forum https://powerusers.microsoft.com/t5/Building-Flows/Using-PowerAutomate-to-Split-and-combine-an-excel-file/m-p/1967055#M216778 hopefully that helps you but keep me posted.
Hi Damian,
What if I have and excel file with 2 tabs (customer and sales), and i want to create multiple excel files with the same number of tabs but split on the value of columns? Lets say that each tab has a column for city.
Thank you
Hi Damian
Thank you for the fantastic videos and scripts. This will make life so much easier for me when I get it working. I have followed your guides and the scripts run however in script 2 I get the following error
We were unable to run the script. Please try again.
Office JS error: Line 18: Workbook addTable: Some header row values have more than 255 characters and will be truncated. Do you want to continue?
clientRequestId: 97a56483-0ea4-45b8-bc5c-d6584c5b1b86
I am not sure how to resolve this, any advice would be greatly appreciated especially as I have no clue regarding coding etc.
Anyone figure out the 255 character issue? Trying to pull from a powerbi data set and getting the same.
what should I do if I need to add a row from bulk worksheet into multiple existing worksheets?
I have a worksheet containing 1000 rows, i need to distribute the data based on key column into 10 existing worksheets already available in a Sharepoint
The script could return arrays of data grouped by your criteria and then you could pass each of those data sets into the respective sheets. Excel is not ideal for this though and you may find yourself battling with files being locked if you use the native actions. Office Scripts or Graph API would be your best bet for larger data volumes. I’ve videos on both for bulk insert on my YouTube.
Create Worksheet based on Data Array , while running this script i got this error : –
Line 8: Cannot read properties of undefined (reading ‘getRangeByIndexes’)\r\nclientRequestId: 8742abc2-dcea-4190-ab5c-9c8025f45027″
I have created a power automate flow same as in the video, but I am getting an error and I don’t know how to fix it. The error occurs when running the second script “Create Worksheet based on Data Array” the error message is as below.
{
“message”: “Our request was invalid\r\nclientRequestId: ae0bdee0-b43a-4a50-a3a1-7e97434daac8”,
“storageErrorCode”: 12
}
Any clue on fixing this?
Can you give instructions on how to set up these functions?
This is awesome, Thank you!. Quick question – I am using the ‘Split Workbook into Data Arrays based on Key Column’ & ‘Create Worksheet based on Data Array’. It’s splits out the files based on a key column and creates individual workbooks but it also creates an extra file with no name just extension (.xlsx). This file has column headers but no data.
Would you know why this is happening. I checked the source file and their are no empty values? This empty file is causing issues with the flow that runs after and send emails. Thanks for you help.
You want to explore the history. Where in the process does this extra file get created. Is it from the initial script, look at the apply to each, how many loops?
Had error message saying cannot open file format or extension is incorrect. Help
Could it be the file extension being missing from filename .xlsx?
I have the file extension, does it matter if I am getting the file from OneDrive instead of Sharepoint? (Newbie here)
Hi Damian,
thank you for you great tutorial and office scripts. Unfortunally I have a problem with the combination of the two scripts (Split Workbook into Data Arrays based on Key Column in combination with Create Worksheet based on Data Array). I built it exactly like in your video but always get the error “Line 9: Cannot read properties of undefined (reading ‘getRangeByIndexes’)\r\nclientRequestId: c1157c0c-6343-4021-ba71-f72be140ee5e” at the end of the flow.
In my opinion it everything runs fine until the last step, as the different excel worksheets are created but not filtered for the key-value but instead populated with all of the unfiltered data.
But be great if you can give me a hint. If you need any further information just let me know.
Thank you and best regards,
Dennis
I’m not sure and would need to see it. Have you shared on a forum?
Not yet, which forum would you prefer?
Thank you for your answer anyway 😉
Hi Damian,
thank you for your reply. I’m not sure if my last answer went through, therefore I “repost” it.
I have not yet shared it on a forum, just wanted to ask at the source 😉
Which forum would you prefer?
Best regards,
Dennis
Best place to share your error is https://powerusers.microsoft.com/ as others beyond myself can support you for free. I get many requests these days and can only provide free support when I’ve time. I can arrange do 1:1 via contact me but I charge for my time. If it was an easy fix I would tell you but I don’t recommend the error.
Okidoki. Thank you
I tried the steps mentioned in the video but it is taking a lot of time.
There are 18 plants information in a master excel workbook which I expect to get split into 18 excel workbooks one for each plant. It has been 20 minutes still it is running neither failed nor successful. Any way I can fasten the process. For reference there are 2 lakh rows in master excel file.