Learn how to build production-ready OCR automation in Power Automate Desktop that extracts structured data from scanned PDFs, images, and live screen regions. Covers text parsing, regex patterns, error handling, and full folder processing pipelines for real-world document workflows.

Picture this: your accounts payable team receives 200 vendor invoices every week. Half arrive as scanned PDFs. The other half are image files attached to emails — JPEGs photographed on someone's phone in a warehouse. Right now, a contractor manually types each invoice number, vendor name, and total amount into your ERP system. That's eight hours of work per week, with a typo rate that keeps your controller up at night.
This is exactly the problem that OCR (Optical Character Recognition) automation solves. Power Automate Desktop includes native OCR capabilities that let you read text from PDFs, screenshots, image files, and live screen regions without any third-party software. When you combine that with structured data extraction logic, you can build flows that process documents in seconds — accurately, consistently, and without anyone staring at a scanner all day.
By the end of this lesson, you'll be able to build complete document processing pipelines in Power Automate Desktop: extracting text from images and PDFs, parsing that text into structured fields, handling messy real-world scan quality, and writing the results to Excel or another destination system. We'll work through a realistic invoice processing scenario from first action to finished flow.
What you'll learn:
This lesson assumes you're comfortable with the Power Automate Desktop interface — creating flows, adding actions, and running tests. You should understand variables, lists, and data tables since we'll be building data tables from extracted content. If you're brand new to the tool, work through Getting Started with Power Automate Desktop first.
You'll also need:
Before you drag a single action onto the canvas, you need to understand what OCR actually does — because misunderstanding this is the root cause of most failed document automation projects.
OCR takes a raster image (pixels) and runs it through an engine that recognizes character shapes. It outputs a string of text. That's it. The engine doesn't understand your document structure; it doesn't know that "INV-2024-00847" is an invoice number or that "$4,230.00" is a total. Your flow code is responsible for that interpretation.
Power Automate Desktop ships with two OCR engines:
Windows OCR — The default engine, built into Windows 10/11 via the Windows.Media.Ocr namespace. It's fast, works offline, and handles typed text very well. It supports multiple languages through Windows language packs. This is the right choice for most document automation.
Tesseract OCR — An open-source engine that you install separately. Tesseract can produce better results on certain document types, particularly older printed documents with unusual fonts, and it supports more languages. The trade-off is it requires a separate installation and configuration step.
Key insight
Neither engine magically extracts structured data. Both return a flat string of characters. Your flow's text-parsing logic determines whether you get clean invoice data or garbage. Invest time in the parsing layer — it's where the real work happens.
Power Automate Desktop's OCR actions fall into two categories:
For most file processing scenarios — the kind where you're reading a folder of PDFs or images — you'll use the file-based approach. The on-screen approach is better suited for automating a document management application where you need to read what's currently displayed.
Let's start with the simplest case: a JPEG or PNG file on disk. Open a new desktop flow and find the Extract text with OCR action under the Computer vision category in the Actions panel.
When you drop it onto the canvas, the configuration dialog has several fields worth understanding:
OCR engine — Choose Windows OCR or Tesseract. For this lesson, we'll use Windows OCR.
OCR source — This is where you specify what to read. Options include:
For file processing, set this to Image file and point it at your file path variable.
Image file path — Set this to a variable that holds your file path, such as %CurrentFilePath%.
OCR language — For Windows OCR, you select a language pack here. English is en-US. This matters: the engine is tuned to the character shapes and word patterns of that language.
Search for text on screen — Leave this unchecked for now. This optional feature lets you wait for specific text to appear rather than just extracting everything.
After configuring and running this action, PAD stores the extracted text in a variable — by default named OcrText. This is a plain text string.
Tip
If your JPEG images are small or low-resolution, pre-process them before OCR. Use the Convert image action (also under Computer vision) to resize images to at least 300 DPI equivalent before passing them to the OCR engine. Small text on a low-res scan is the single biggest cause of garbage OCR output.
Here's what a basic image extraction flow looks like:
Set variable: ImagePath = "C:\Invoices\INV_2024_00847.jpg"
Extract text with OCR:
- OCR engine: Windows OCR
- OCR source: Image file
- Image file path: %ImagePath%
- Language: en-US
→ Stores result in: OcrText
Display message: %OcrText%
Run this and you'll see raw extracted text in a message dialog. Before writing any parsing logic, always do this sanity check first. The raw output tells you exactly what you're working with.
Here's something that catches most people: Power Automate Desktop cannot directly OCR a PDF file. The Extract text with OCR action expects an image. You have two paths forward depending on your PDF type:
Path 1: Text-based PDFs — If your PDF was created digitally (not scanned), it already contains embedded text that can be extracted without OCR. Use the Extract text from PDF action under the PDF category instead. This is faster and more accurate than OCR because you're reading the actual text data, not inferring it from pixels.
Path 2: Scanned PDFs (image-based) — If your PDF is a scan, you need to convert each page to an image first, then OCR that image. Use this sequence:
Extract pages from PDF:
- PDF file: %PdfFilePath%
- Page range: All
- Extract pages as images
- Image folder: "C:\Temp\PDFPages\"
→ Stores list of image paths in: PdfPageImages
For each ImagePath in PdfPageImages:
Extract text with OCR:
- OCR engine: Windows OCR
- OCR source: Image file
- Image file path: %ImagePath%
- Language: en-US
→ Stores result in: PageOcrText
Set variable: FullDocumentText = %FullDocumentText% + %PageOcrText% + " "
Warning
When you extract PDF pages as images, PAD saves them as individual files in your specified folder. Make sure that folder exists before running the flow, or add a Create folder action first. Also clean up these temporary image files at the end of your flow — in a high-volume scenario, you'll fill up your C: drive faster than you'd expect.
The FullDocumentText variable now contains all the extracted text from every page, concatenated. For a single-page invoice, this is straightforward. For a 12-page contract, you may want to store pages separately.
Getting the raw text is the easy part. Extracting meaning from it requires deliberate logic. Let's work through a realistic invoice parsing scenario.
Assume your OCR extracted this text from an invoice:
Northgate Supplies Ltd
123 Industrial Way, Chicago IL 60601
INVOICE
Invoice Number: INV-2024-00847
Invoice Date: November 14, 2024
Due Date: December 14, 2024
Bill To:
Acme Corporation
456 Business Park Drive
Chicago, IL 60602
Description Qty Unit Price Total
Industrial Fasteners (Box) 50 $12.50 $625.00
Safety Gloves (Pair) 100 $8.75 $875.00
Steel Brackets 25 $108.40 $2,710.00
Subtotal: $4,210.00
Tax (5%): $210.50
Total Due: $4,420.50
You need to extract: Invoice Number, Invoice Date, Vendor Name, and Total Due. Let's tackle each one.
For fields with a consistent label-value pattern, the Get subtext action works well. The logic is: find the label, then grab everything after it until a newline.
# Extract Invoice Number
Get subtext:
- Original text: %OcrText%
- Start: After text "Invoice Number: "
- End: Before next occurrence of newline
→ Stores result in: InvoiceNumber
# Result: "INV-2024-00847"
PAD's Get subtext action lets you specify a start and end delimiter as literal text or position. For end delimiter, use \n for newline (make sure to enable the "treat \n as newline" option in the action, or use a variable containing a newline character).
Tip
Create a dedicated variable NewLine = "\n" at the top of your flow using Set Variable, then reference %NewLine% as your end delimiter throughout. This is cleaner than trying to embed newline characters in action config dialogs.
When your documents have slight formatting variations — sometimes "Invoice #:" sometimes "Invoice Number:" sometimes "Inv No." — hardcoded string matching breaks. This is where regex (regular expressions) becomes your best friend.
Power Automate Desktop has a Find text in text action and a Parse text action. The Parse text action supports regex mode. Here's how to extract the invoice number using a pattern that matches common formats:
Parse text:
- Text to parse: %OcrText%
- Text to find: (INV|Inv|Invoice)[-\s#]*([\d]{4}-[\d]{2}-[\d]{5}|[\d]{6,})
- Use regular expressions: Yes
- Store first match only: Yes
→ Stores match in: InvoiceNumberMatch
For the total amount, a currency-focused pattern handles the "$4,420.50" format:
Parse text:
- Text to parse: %OcrText%
- Text to find: Total Due:\s*\$?([\d,]+\.\d{2})
- Use regular expressions: Yes
→ Stores match in: TotalDueMatch
Key insight
Build and test your regex patterns outside PAD first. Use a tool like regex101.com where you can paste your actual OCR output and iterate on your pattern until it matches correctly. OCR text often has unexpected spaces or line breaks, so test against real OCR output, not the original clean document.
One important nuance: PAD's regex support is based on .NET regex syntax. Most common patterns work identically, but if you're coming from Python's re module, note that lookbehind in .NET allows variable-length patterns while Python's does not. For our purposes, the basics are the same.
The vendor name is the trickiest field because it appears at the top of the document without a label — it's just the first line of text. Here's the approach:
Get subtext:
- Original text: %OcrText%
- Start: Beginning of text (position 0)
- End: Before first occurrence of newline
→ Stores result in: VendorName
# Trim any leading/trailing whitespace
Trim text:
- Text to trim: %VendorName%
→ Stores result in: VendorName
This works reliably when your documents consistently put the vendor name first. If they don't, you may need to key off a landmark like "Bill To:" and work backwards.
Now let's scale this up to process an entire folder of invoices automatically. This is where it becomes genuinely useful. We'll build a flow that reads every PDF and image file from a folder, extracts the four key fields, and writes them to an Excel spreadsheet.
Here's the complete flow structure:
# ── SETUP ──────────────────────────────────────────────
Create new list: ExtractedData (empty)
Set variable: InvoiceFolder = "C:\Invoices\Incoming\"
Set variable: OutputExcel = "C:\Invoices\Extracted_Data.xlsx"
Set variable: TempImageFolder = "C:\Temp\OCRWorking\"
Create folder if not exists: %TempImageFolder%
# ── GET FILES ──────────────────────────────────────────
Get files in folder:
- Folder: %InvoiceFolder%
- File filter: *.pdf;*.jpg;*.jpeg;*.png;*.tif;*.tiff
- Include subfolders: No
→ Stores result in: InvoiceFiles
# ── PROCESS EACH FILE ──────────────────────────────────
For each CurrentFile in InvoiceFiles:
Set variable: RawText = ""
Set variable: FileExtension = (get extension of CurrentFile)
# Handle PDFs differently from images
If FileExtension = ".pdf":
# First, try text-based extraction
Extract text from PDF:
- PDF file: %CurrentFile%
- Page range: All
→ Stores in: PdfText
# If extracted text is empty, it's a scanned PDF
If length of PdfText < 50:
Extract pages from PDF as images:
- PDF file: %CurrentFile%
- Output folder: %TempImageFolder%
→ Stores image paths in: PageImages
For each PageImage in PageImages:
Extract text with OCR:
- OCR source: Image file
- Image file path: %PageImage%
- Language: en-US
→ Stores in: PageText
Set variable: RawText = %RawText% + %PageText% + " "
Delete files: %TempImageFolder%\*.png
Else:
Set variable: RawText = %PdfText%
Else:
# It's a direct image file
Extract text with OCR:
- OCR source: Image file
- Image file path: %CurrentFile%
- Language: en-US
→ Stores in: RawText
# ── PARSE FIELDS ───────────────────────────────────────
# Invoice Number
Parse text (regex): (INV|Inv)[-\s#]*([\w\d-]+)
in %RawText% → InvoiceNumber
# Invoice Date
Parse text (regex): Invoice Date:\s*(\w+ \d+, \d{4}|\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4})
in %RawText% → InvoiceDate
# Vendor Name (first line)
Get subtext of %RawText% from start to first newline → VendorName
Trim: VendorName
# Total Due
Parse text (regex): Total Due:\s*\$?([\d,]+\.\d{2})
in %RawText% → TotalDue
# ── STORE RESULT ───────────────────────────────────────
Create new data row:
- File: %CurrentFile.FileName%
- VendorName: %VendorName%
- InvoiceNumber: %InvoiceNumber%
- InvoiceDate: %InvoiceDate%
- TotalDue: %TotalDue%
Add row to list: ExtractedData
# ── WRITE TO EXCEL ─────────────────────────────────────
Launch Excel: %OutputExcel%
Write data table to Excel worksheet starting at cell A1: ExtractedData
Save and close Excel
This pseudocode maps directly to PAD actions. The key architectural decision here is the "try text first, fall back to OCR" pattern for PDFs — this saves significant processing time because text-based PDF extraction is orders of magnitude faster than OCR.
Note
If you're writing results to Excel, check out the Automating Excel with Power Automate Desktop lesson for the exact actions and their configuration options. Excel automation has some quirks with header rows and data table writes that are worth understanding before you deploy.
The file-based approach covers most document processing scenarios. But sometimes your documents live inside an application — a document management system, an ERP viewer, a legacy Windows app. You can't export them to a file without a lot of clicking. That's where on-screen OCR shines.
The Extract text with OCR action with source set to Specific window element or Current screen reads text directly from what's displayed on screen. You define a rectangular region (in pixels) and the engine captures and OCRs that area.
The practical workflow:
Extract text with OCR:
- OCR engine: Windows OCR
- OCR source: Foreground window
- Window: "Invoice Viewer - Acme ERP"
- Restrict to area: Yes
- X: 120, Y: 340, Width: 600, Height: 80
→ Stores result in: InvoiceNumberRegion
This is particularly useful for automating legacy systems where UI Automation can't reliably identify the text fields — perhaps because the application renders text as graphics, not as actual text controls.
Tip
When using on-screen OCR with coordinate-based regions, document the screen resolution assumption in a comment action. If this flow ever runs on a machine with a different display scaling setting, your coordinates will be off. Consider adding a check at flow startup that validates the screen resolution matches expectations.
Real documents are messy. Scans are skewed, coffee-stained, or low-contrast. Handwritten annotations interfere with printed text. The OCR engine will sometimes extract garbage. Your flow needs to survive this gracefully.
The Error Handling in Desktop Flows lesson covers the full mechanics, but here are the patterns that matter most for OCR workflows:
Never write OCR output directly to a destination without validation. After each parsing step, check that what you got looks reasonable:
# Validate invoice number was found
If InvoiceNumber = "" or InvoiceNumber = "N/A":
# Log to an error table
Add row to ErrorLog: (CurrentFile, "Invoice number not extracted", RawText)
Set variable: SkipThisFile = True
# Validate total due is a number
Convert text to number: %TotalDue% → TotalDueNumeric
If error occurred during conversion:
Add row to ErrorLog: (CurrentFile, "Total amount parse failed: " + TotalDue, "")
Set variable: SkipThisFile = True
OCR can fail outright if a file is corrupt, password-protected, or in an unsupported format. Wrap your extraction actions in an error handling block:
On block error:
Add row to ErrorLog: (CurrentFile, "OCR failed: " + LastErrorMessage, "")
Continue to next iteration
[Begin block]
Extract text with OCR: ...
[End block]
This keeps your loop running even when one file causes an exception.
Always maintain a separate error log. At the end of the flow, write it to a second Excel sheet. This gives your team a clear picture of which files need manual review — much better than silently skipping failures.
If count of ErrorLog rows > 0:
Write ErrorLog to Excel worksheet "Errors" in %OutputExcel%
Send email notification: "Invoice processing completed. %ErrorCount% files require review."
Let's build this end-to-end. Here's a complete exercise with specific deliverables.
Scenario: You've been asked to automate extraction of invoice data for your finance team. Invoices arrive as a mix of scanned PDFs and photographed JPEGs in a shared folder. You need to extract four fields from each and populate an Excel tracker.
Step 1: Prepare your test documents
Create 5-10 test documents with a consistent invoice format. If you don't have real invoices, create PDF exports from a Word template, then print-to-PDF (to get text-based PDFs) and also scan one or two (or photograph them with your phone) to create genuine scanned versions.
Put them all in C:\TestInvoices\Incoming\ with a mix of .pdf, .jpg, and .png extensions.
Step 2: Build the raw extraction test
Before building the full loop, create a simple flow that:
Run this on each of your test files. Note variations in how the OCR renders the same content. This is your baseline for writing parsing logic.
Step 3: Write and test your parsing logic
Working from the raw OCR output you captured in Step 2, write regex patterns for each field. Test them using PAD's "Parse text" action with test data directly in the action configuration. Confirm each pattern returns the right result before wiring it into the loop.
Step 4: Build the folder loop
Implement the full folder processing flow from the architecture described earlier:
Step 5: Introduce deliberate errors
Test your error handling by including:
.pdf extension (should fail on PDF extraction)Verify your error log captures all three failures while the valid files still process successfully.
Deliverable: A flow that processes a mixed folder of invoices, writes extracted data to ExtractedInvoices.xlsx, writes failures to an Errors sheet in the same file, and leaves no unhandled exceptions.
OCR accuracy on a 200 DPI scan of a fax that's been photocopied three times is going to be terrible, and no amount of clever parsing logic will fix it. Set realistic expectations: if the source document is low quality, the output will be low quality. Where possible, work upstream to improve scan quality rather than downstream to handle extraction failures.
Fix: Add an image pre-processing step. Power Automate Desktop doesn't have built-in image enhancement, but you can call a command-line tool like ImageMagick to increase contrast and resolution before passing the file to OCR.
"Invoice Number: INV-2024-00847" works great until one vendor sends "Invoice #: INV-2024-00847" or "Inv. No.: INV-2024-00847". Your hardcoded Get subtext after "Invoice Number: " returns nothing, and your validation catches it — but now you have a pile of manually-reviewed files.
Fix: Use regex patterns that account for common variations from the start. It takes five minutes longer to write but saves hours of exception handling later.
The convert-PDF-to-images step creates PNG files in your temp folder. If you're processing 200 invoices and each has 2 pages, you've just created 400 temporary files. If the flow errors mid-run, those files persist. Next run, they get mixed with the new files.
Fix: At the start of each file iteration, clear the temp folder. At the end of the entire flow, clear it again. Use Delete files with a wildcard pattern.
If you're extracting text from a French or German document with the engine set to en-US, you'll get character substitutions on accented letters. "Société" might come back as "Soci-t-" or similar.
Fix: Either detect document language from metadata and set the OCR language dynamically, or use a universal character set. If your documents are consistently in a single non-English language, just set the language pack appropriately.
This happens when people try to pass %OcrText% somewhere that expects a file path. The OCR action outputs a text string containing the extracted content — not a path to a file containing the content. It's a variable, not a reference.
Fix: Work with %OcrText% using text manipulation actions (Parse text, Get subtext, Trim, etc.), not file actions.
Warning
Be careful with very large documents. If you're concatenating OCR output from a 50-page PDF into a single variable, you may end up with an enormous string that makes subsequent Parse text operations slow. For long documents, consider processing page by page and writing partial results after each page rather than building one giant string.
If your extraction returns an empty OcrText variable:
OcrText and compare it carefully with your regex pattern — OCR often inserts extra spaces or breaks words unexpectedlyYour desktop flow handles the local extraction beautifully. But for production deployments, you'll want to integrate this into a broader automation ecosystem. A common pattern is:
The desktop flows and RPA overview article covers the cloud-to-desktop trigger mechanism in detail. If you need your extracted data to feed into an approval workflow — for example, flagging invoices over $5,000 for manager review — you can connect the output directly to Power Automate approval workflows.
For high-volume document processing where you're receiving thousands of files daily, also consider subflows to organize your OCR logic into reusable components. The parsing logic for invoices, the parsing logic for purchase orders, and the parsing logic for delivery receipts can each live in their own subflow — called from a main orchestrator flow that handles file routing. This keeps your flows maintainable as your document library grows.
Note
If your documents contain sensitive financial or personal data, think carefully about where temporary image files land during PDF processing. That C:\Temp\OCRWorking\ folder shouldn't be on a shared drive, and it should be cleaned up immediately after each document is processed — not just at the end of the batch.
You've covered a lot of ground. Here's what you now know how to do:
OCR mechanics — You understand the difference between Windows OCR and Tesseract, when to use each, and what the engine actually returns (a flat text string, not structured data).
File type handling — You can extract text from image files directly, from text-based PDFs using the PDF action, and from scanned PDFs using the convert-to-image-then-OCR pipeline.
Text parsing — You can extract named fields from raw OCR output using Get subtext for simple label-value patterns and regex for variable formats. You know to build and test regex patterns against actual OCR output.
Production-grade loops — You can process a whole folder of mixed document types, handle each correctly, write structured results to Excel, and maintain an error log for documents that need manual review.
Error handling — You know how to validate extracted fields, wrap OCR actions in error blocks, and build flows that degrade gracefully when documents are corrupted or unclear.
Where to go next:
The most immediate improvement you can make is investing in your parsing patterns. The more document types you process, the more you'll learn about the specific variations in your vendor invoices or customer forms — encode those learnings into your regex library.
From a flow architecture perspective, explore subflows and reusable logic to keep your document processing flows organized as they grow. And when you're ready to connect your desktop OCR flow to the broader Microsoft Power Platform ecosystem — sending results to Dataverse, triggering approvals, or archiving documents to SharePoint — the desktop flows and legacy automation overview will show you the connection points.
Document processing automation is one of those areas where a few hours of flow-building genuinely transforms someone's workday. The accounts payable contractor who used to spend eight hours a week typing invoice data? With a well-built OCR flow, that becomes a 20-minute exception review process. That's the kind of impact that makes RPA worth learning.