Learn how to read CSV and text files in Power Automate Desktop, parse delimited records, handle header rows correctly, and write processed data back to files. A hands-on guide for automating flat-file workflows from first principles.

Picture this: your company's legacy inventory system exports a flat CSV file every morning at 6 AM — 3,000 rows, comma-separated, with a header row at the top. Your job is to read that file, filter out discontinued items, and push the remaining records into a web portal one by one. Nobody wants to do that manually. That's exactly the kind of task Power Automate Desktop was built to handle.
CSV (Comma-Separated Values) and plain text files are the lingua franca of data exchange. They show up everywhere: bank exports, ERP system dumps, legacy application outputs, lab instrument readings, HR roster files. Even when the rest of the world has moved to APIs and databases, someone, somewhere, is still dropping a .csv onto a network share and expecting another system to pick it up. Being able to read, parse, and write those files inside a desktop flow is one of the most immediately useful skills you can add to your automation toolkit.
By the end of this lesson, you'll be able to open a CSV or text file in Power Automate Desktop, split it into structured rows and columns, skip or use the header row correctly, loop through every record to perform actions, and write new data back to a file. We'll use a realistic scenario throughout: processing a daily sales report exported from a point-of-sale system.
What you'll learn:
This lesson assumes you've already installed Power Automate Desktop and can create and run a basic flow. If that's new to you, start with Getting Started with Power Automate Desktop: Installing, Recording, and Running Your First Desktop Flow before continuing here.
You should also have a working understanding of variables and lists in PAD. If terms like "list," "index," and "loop variable" feel unfamiliar, read Variables, Lists, and Data Tables in Power Automate Desktop: A Complete Practitioner's Guide first — this lesson builds directly on those concepts.
Before touching any actions in the designer, let's make sure you have a clear mental model of what you're working with.
A CSV file is just a plain text file. Open one in Notepad and you'll see something like this:
OrderID,CustomerName,Product,Quantity,UnitPrice,Status
1001,Fernanda Oliveira,Bluetooth Headset,2,49.99,Completed
1002,James Whitfield,USB-C Hub,1,34.95,Pending
1003,Aiko Tanaka,Mechanical Keyboard,1,89.00,Completed
1004,Ravi Patel,Webcam HD,3,62.50,Cancelled
Each line is a record (a row of data). Within each line, values are separated by a delimiter — in this case, a comma. The first line is often a header row containing column names rather than actual data.
Power Automate Desktop doesn't have a magical "read CSV" button that hands you a tidy table. Instead, you read the file as raw text, then use string manipulation actions to break it into the structure you need. Once you understand that two-step process — read then parse — everything else clicks into place.
Note
Some CSV files use other delimiters. Pipe-delimited files (|) are common in financial systems. Tab-delimited files (TSV) show up in database exports. The parsing technique is identical regardless of delimiter — you just swap the separator character.
Open Power Automate Desktop and create a new flow. Call it something like Process Daily Sales Report.
In the Actions panel on the left, expand the File category. Find the action called Read text from file and drag it onto your canvas.
Configure the action with these settings:
C:\Reports\daily_sales.csvThe action will produce a variable — by default named FileContents — that holds the entire raw text of the file as a single string. Think of it as having copied everything from Notepad and pasted it into one variable.
Tip
If you're working with a file whose path changes daily (like sales_2024-07-15.csv), build the path dynamically using the Get current date and time action combined with text formatting. That way your flow picks up the right file automatically without you editing the path each morning.
At this point, FileContents looks like one big blob of text with newline characters (\n or \r\n) separating the rows. That's your starting point.
Now you need to break that blob into individual rows. You'll use the Split text action, found in the Text category of the Actions panel.
Configure it like this:
%FileContents%The action produces a list variable — call it AllRows. Each item in the list is one line of the file. So AllRows[0] is the first line (your header row), AllRows[1] is the first data row, and so on.
Warning
Windows line endings are \r\n (carriage return + newline), while Unix/Linux line endings are just \n. PAD's built-in "New line" delimiter handles both, but if you're splitting manually using a custom delimiter, make sure you account for the \r that might be hiding at the end of each value. You'd see this as a trailing invisible character causing text comparisons to fail mysteriously.
If your file uses a pipe or tab delimiter for the rows themselves (unusual, but it happens), you can choose Custom delimiter and enter whatever character separates your rows.
This is where beginners make their first major mistake: they loop through every item in AllRows including the header, then wonder why their first "record" has column names instead of values.
You have two strategies.
Strategy A — Skip by index. Start your loop at index 1 instead of 0. The header is at index 0 and you just never touch it. Simple and effective.
Strategy B — Extract and use the header. Before your loop, grab AllRows[0], split it by your column delimiter (comma in our case), and store the resulting list as Headers. Then start your data loop at index 1. This is useful when you need to reference columns by name or write the header into your output file.
For our sales report scenario, we'll use Strategy B because we want to preserve the header when we write our output file.
Add another Split text action:
%AllRows[0]%,HeadersNow Headers[0] is OrderID, Headers[1] is CustomerName, Headers[2] is Product, and so on.
Here's where the real work happens. You'll use a For each loop to iterate through AllRows, but you need to skip the header. The cleanest way to do this is with a Loop action (which gives you index control) rather than For each.
In the Actions panel, find Loops → Loop. Configure it:
1 (skipping index 0, the header)%AllRows.Count - 1%1RowIndexInside the loop, add a Split text action to break the current row into individual fields:
%AllRows[RowIndex]%,CurrentRowNow inside each loop iteration, CurrentRow[0] is the OrderID, CurrentRow[1] is the CustomerName, CurrentRow[2] is the Product, CurrentRow[3] is the Quantity, CurrentRow[4] is the UnitPrice, and CurrentRow[5] is the Status.
You can assign these to named variables to make your flow more readable:
OrderID, Value: %CurrentRow[0]%CustomerName, Value: %CurrentRow[1]%This is optional but makes downstream actions much easier to understand when you come back to the flow six months later.
Key insight
List indexing in Power Automate Desktop is zero-based, meaning the first item is at index [0], not [1]. This trips up people coming from environments like Excel where rows start at 1. When you split a row with five columns, valid indices are 0, 1, 2, 3, and 4.
Now that you have clean field values, you can do something with them. In our sales scenario, let's say we want to process only "Completed" orders — we'll skip Pending and Cancelled records, and for each Completed order we'll calculate the line total and prepare it for output.
Inside your loop, after the split action, add an If condition:
%CurrentRow[5]%=CompletedInside the If block, add a Set variable action:
LineTotal%CurrentRow[3] * CurrentRow[4]%PAD will automatically evaluate the arithmetic expression. CurrentRow[3] is Quantity (a number stored as text) and CurrentRow[4] is UnitPrice. PAD is usually smart enough to coerce text to numbers for arithmetic, but if you're getting errors, add a Convert text to number action before multiplying.
This pattern — split the row, check a condition, do something — is the backbone of virtually every CSV-processing flow you'll ever build. Whether you're entering records into a web portal (check out Web Automation in Power Automate Desktop: Browser Actions, Form Filling, and Data Extraction), pushing data into a desktop application, or aggregating totals, this loop structure handles it.
Tip
For complex business logic inside the loop — validation, multiple conditions, lookups — consider wrapping the loop body in a subflow. Your main flow stays clean and readable, and the processing logic lives in a named, reusable block. The article on Subflows and Reusable Logic in Power Automate Desktop covers exactly how to set that up.
Reading and processing records is only half the job. Now you need to write results back to a file. Let's create a filtered output CSV containing only the Completed orders, plus a new LineTotal column.
Setting up the output string
Before your loop, create a variable to accumulate your output:
OutputContent, Value: OrderID,CustomerName,Product,Quantity,UnitPrice,LineTotalThis seeds your output with a header row. Note we're adding LineTotal as a new column.
Appending inside the loop
Inside your loop, within the "Completed" If block, after calculating LineTotal, add another Set variable action to build a new CSV row:
NewRow%CurrentRow[0]%,%CurrentRow[1]%,%CurrentRow[2]%,%CurrentRow[3]%,%CurrentRow[4]%,%LineTotal%Then append this row to your output string using another Set variable:
OutputContent%OutputContent%%NewLine%%NewRow%%NewLine% is a built-in PAD variable that inserts a proper line ending. Always use this instead of trying to type \n literally — it ensures your output file will be readable across systems.
Writing the file
After your loop completes, use the Write text to file action from the File category:
C:\Reports\completed_orders.csv%OutputContent%Run the flow and then open completed_orders.csv in Excel. You'll see a clean, properly formatted file with only the Completed orders and the calculated line totals.
Real-world CSV files are rarely as clean as our example. Here are the situations you'll actually encounter.
Quoted fields containing commas
A value like "Smith, John" is a legitimate CSV field — the quotes tell parsers to treat the comma inside as literal content. PAD's basic Split text action doesn't understand this and will incorrectly split "Smith, John" into two fields.
For files with quoted fields, you have two options: use a Run PowerShell script action to leverage .NET's built-in CSV parser, or preprocess the file to remove problematic commas. The Scripting Inside Desktop Flows: Running PowerShell, Python, and VBScript Actions article shows you how to execute scripts directly from PAD when you need more parsing power.
Empty lines at the end of the file
Many systems append a trailing newline after the last record. When you split by new line, you'll get an empty string as the last item in AllRows. Before processing each row inside your loop, add a condition:
%AllRows[RowIndex]% is not equal to `` (empty string), then proceedThis prevents errors when you try to split an empty line.
Files with no header row
Some legacy systems export headerless files. In that case, start your loop at index 0 instead of 1, and simply don't extract a Headers list. Your column indices still work the same way — you just need to know the column order from the system documentation or by inspecting a sample file.
Warning
Never assume a file's column order is stable without checking. Legacy systems sometimes add or reorder columns after upgrades. Build a quick validation step into your flow that confirms the header row contains the columns you expect before processing begins. If column 3 is suddenly "Category" instead of "Quantity," you want the flow to fail loudly rather than silently process wrong data.
Pipe and tab delimiters
If your file uses | as a delimiter, every Split text action that was set to , should be changed to |. For tab-delimited files, in the Custom delimiter field you'll need to enter an actual tab character. The easiest way to get a tab character into PAD is to use %TabChar% — another built-in PAD special variable — as your delimiter value.
Create a fresh flow called Filter Inventory Report and work through these steps:
inventory.csv in C:\Practice\ with this content:SKU,ProductName,Category,StockQty,ReorderLevel,Active
SKU001,Wireless Mouse,Peripherals,45,10,Yes
SKU002,17in Monitor,Displays,3,5,Yes
SKU003,Fax Machine,Legacy,0,0,No
SKU004,USB Keyboard,Peripherals,12,8,Yes
SKU005,VGA Cable,Legacy,88,0,No
Build a flow that reads this file, loops through all rows (skipping the header), and filters for rows where Active equals Yes AND StockQty is less than or equal to ReorderLevel (items that are active and need reordering).
For matching rows, build an output CSV called reorder_alert.csv in C:\Practice\ with columns: SKU, ProductName, StockQty, ReorderLevel.
Run the flow. Your output file should contain only SKU002 (Monitor — stock 3, reorder level 5).
Bonus challenge: Add a third column to your output called ShortfallQty that contains ReorderLevel - StockQty for each flagged item.
"Index out of range" errors
This almost always means you're trying to access CurrentRow[5] but the row only has 5 columns (indices 0–4). Either the row has fewer columns than expected, or an empty row snuck in. Add the empty-row check described above and verify your expected column count against the actual file.
Numbers not calculating correctly
PAD stores everything from a text file as a string. If %CurrentRow[3] * CurrentRow[4]% gives you an error, use Convert text to number on both values before multiplying, then store them in numeric variables.
The output file is missing its last record
Check whether you're off by one in your loop's end condition. %AllRows.Count - 1% is correct because Count gives you the total number of items, and the last valid index is always Count minus one (zero-based indexing).
The output file looks fine in Notepad but Excel shows everything in one column
Excel needs to know your delimiter. Either save the file with a .csv extension and double-click (Excel reads commas by default in most locales), or use Excel's Data → Text to Columns feature. For reliable Excel compatibility, consider writing data directly to an Excel file using the Excel actions covered in Automating Excel with Power Automate Desktop: Reading, Writing, and Running Macros.
Flow errors on files with special characters (accents, symbols) This is an encoding mismatch. The file is probably Latin-1 or Windows-1252 but you're reading it as UTF-8. Change the encoding setting in the Read text from file action to match your file's actual encoding. If you're unsure, open the file in Notepad, choose "Save As," and check what encoding Notepad reports in the dropdown.
Tip
When building flows that will run unattended overnight, wrap your entire file-reading and parsing logic in an error-handling block. If the source file is missing or malformed, you want the flow to send you an alert rather than silently succeed with zero records processed. The lesson on Error Handling in Desktop Flows: On Block Error, Retry Policies, and Recovery Screenshots shows you exactly how to do this.
You've now built a complete CSV processing pipeline in Power Automate Desktop. Here's the pattern you'll use again and again:
%NewLine% to separate rowsThis foundation handles the majority of flat-file automation scenarios you'll encounter in the real world. From here, several natural next steps open up:
Flat files aren't glamorous, but mastering them makes you immediately useful in almost any enterprise environment. The technique you've learned here — read, split, loop, write — is a transferable pattern that shows up in PDF parsing, log file analysis, and anywhere else structured text needs to be turned into action.
Power Automate Desktop & RPA
Automating Image-Based UI Interactions in Power Automate Desktop: Using Screen Scraping, Image Recognition, and Coordinate-Based Actions When Selectors Fail
Automating Internet Explorer and Citrix-Hosted Applications in Power Automate Desktop: Selector Strategies, Session Management, and Reliable Data Extraction from Virtual Environments