I wanted a flow that takes a PowerPoint template full of {{Placeholders}}, swaps in real client data, and spits out a finished, on-brand sales deck — all from a single button press. The clever bit is that the actual find-and-replace code is written for me by an AI prompt inside Power Platform. It worked… mostly. A couple of placeholders stubbornly refused to replace, and the fix taught me something genuinely useful about how PowerPoint stores text. Let me walk you through it.


The Idea: A Prompt That Writes the Code

Rather than hand-writing Python to edit a .pptx, I let a Power Platform prompt do the heavy lifting. I describe the rules in plain English, pick a model, and the prompt generates and runs the code that manipulates the file. Here’s the prompt I built — “Populate Client Sales Deck Template”:

The Power Automate prompt named ‘Populate Client Sales Deck Template’ showing the plain-English replacement rules and the GPT-4.1 model selection

The beauty here is the no-code-to-pro-code spectrum in action: I’m not writing a script, I’m writing instructions. The prompt turns those instructions into working code behind the scenes.

Grab the Prompt

Want to reuse it? Here’s the full, battle-tested prompt. You can download it as a text file or expand the box below to copy and paste it straight into your own Power Platform prompt.

📋 Click to expand the full prompt
You will replace placeholder values inside a PowerPoint template.

IMPORTANT RULES FOR REPLACEMENT:

1. Placeholders use double curly braces: {{ClientName}}, {{Revenue}}, {{Owner}}.

2. Replace placeholders wherever they appear: whole values, inside sentences, multiple
   times per slide, inside grouped shapes (recurse into GroupShape, type 6), and inside
   table cells.

3. CRITICAL — placeholders are frequently split across multiple runs. PowerPoint often
   fragments a token like {{ClientName}} into several runs (e.g. ' {{', 'ClientName', '}}').
   You MUST NOT match on a single run's text. For each paragraph, reconstruct the full
   paragraph string by concatenating ALL run texts, and locate placeholders in that
   combined string.

4. CRITICAL — preserve per-run formatting using span-based replacement. Do NOT collapse
   the paragraph into one run. Many paragraphs contain highlighted/bold/coloured words
   that must keep their formatting. To replace a placeholder that spans runs:
     - Compute the character offset of each run within the concatenated paragraph text.
     - Find the placeholder's start and end character positions, and determine which run
       the match starts in and which run it ends in.
     - Write the replacement value into the start run only: set its text to
       (text before the match in the start run) + value. The value thus inherits the
       placeholder's own run formatting.
     - Set the end run to (text after the match in the end run).
     - Set any runs strictly between the start and end runs to empty string "".
     - Leave ALL other runs in the paragraph completely untouched, preserving their fonts,
       colours, highlights, bold, etc.
     - If the placeholder starts and ends in the same run, just do an in-place substring
       replace on that single run.
     - Repeat until no further occurrences of the token remain in the paragraph (to handle
       multiple occurrences).
     - NEVER assign to shape.text or text_frame.text, and NEVER move all paragraph text
       into run[0] and blank the rest — that destroys mixed formatting.

5. For each token, replace ALL occurrences of {{TokenName}} with its value; leave no
   placeholders behind, including split ones.

6. If a placeholder is not found, log it and continue.

7. Process ALL text frames in ALL shapes, nested group shapes, and table cells on every
   slide (restrict to a specific slide only if one is explicitly provided).


TOKENS
Token Name      | Description                                                   | Page | Value
ClientName      | Name of the customer or organisation the deck is prepared for | 01   | ClientName
AccountManager  | Person responsible for the account / primary contact          | 01   | AccountManager
Date            | Presentation or proposal date                                 | 01   | Date
Industry        | Customer's industry or sector                                 | 02   | Industry
Revenue         | Customer's annual revenue or company size indicator           | 02   | Revenue
Region          | Primary geography or operating region                         | 02   | Region
PackageName     | Name of the recommended solution/package                      | 03   | PackageName
Price           | Total investment or pricing for the package                   | 03   | Price
Discount        | Discount applied to the recommendation                        | 03   | Discount
Owner           | Person responsible for follow-up / ongoing engagement         | 04   | Owner
FollowUpDate    | Date by which the owner will follow up                        | 04   | FollowUpDate


INPUT
PowerPoint template file named Template.

OUTPUT
A modified PowerPoint file with all placeholders replaced.

The Flow: Wiring It All Together

The flow itself is refreshingly simple. A manual trigger collects the field values (Client Name, Account Manager, Price, Discount and so on), I grab the template file, hand everything to the Run a prompt action, then compose and save the finished deck back to SharePoint.

The Power Automate flow showing Manually trigger a flow, Get file content, Run a prompt with the input fields, Compose, and Create file

Each input — Industry, Region, FollowUpDate, AccountManager, Owner — maps to a {{Token}} in the slide. The template comes in as base64, the prompt does its magic, and out pops a populated presentation.


The Template: Branded Placeholders

This is the part I’m most pleased with. The template isn’t just plain text — it’s a properly designed, branded slide with highlighted package names, coloured prices and discounts. The placeholders sit right inside that styling:

A PowerPoint slide showing branded placeholders including a highlighted {{PackageName}}, and {{Price}} and {{Discount}} in coloured text within a sentence

Notice {{PackageName}} has that teal highlight, {{Price}} is in brand blue, and {{Discount}} is orange. That formatting matters — and it’s exactly what nearly tripped me up.

Want to follow along? Download the reusable template and try it with the prompt above.


The Gotcha: Placeholders Split Across “Runs”

Here’s where it got interesting. Most placeholders replaced perfectly, but {{ClientName}} and {{AccountManager}} were ignored every single time. The code looked correct. So why?

What’s a “run”, in layman’s terms?

When you type text into PowerPoint, it doesn’t store a sentence as one tidy string. Behind the scenes it chops your text into little chunks called runs, and it creates a new chunk every time anything changes — a different colour, a bold word, or even just where the spell-checker drew a wavy red line.

So even though you see {{ClientName}} as one word on the slide, PowerPoint might secretly be storing it as three separate pieces:

[' {{']  ['ClientName']  ['}}']

My original code was checking each piece on its own, asking “does this chunk contain {{ClientName}}?” — and the answer was always no, because no single chunk held the whole thing. The placeholder was hiding in plain sight, split across the seams.

The ones that did work ({{Date}}, {{Industry}}) just happened to land in a single tidy chunk. Pure luck.

Fix attempt #1: Glue the chunks together

The first fix was to stop reading chunk-by-chunk. Instead, I told the prompt to glue all the chunks in a paragraph back together into one string, do the replacement on that, then write the result back. That instantly fixed the missing placeholders. 🎉

But it introduced a new problem…

Fix attempt #2: Don’t flatten my formatting

My first rewrite wrote the whole repaired sentence back into the first chunk and emptied the rest. That works for plain text — but remember those highlighted, colourful placeholders? Flattening everything into one chunk meant the entire paragraph took on a single style. My lovely teal {{PackageName}} and orange {{Discount}} lost their colours and collapsed into one boring line.

The final fix was subtler: replace the placeholder only within the specific chunks it actually occupies, and leave every other chunk — and its formatting — completely untouched. The replacement value drops into the placeholder’s own chunk, so $100,000 inherits the blue, 10% keeps its orange, and the surrounding narrative stays exactly as designed.


The Result: A Personalised Deck in Seconds

With the prompt rewritten, every field injects at run-time and the branding survives intact:

The finished, populated slide showing ‘Automation Experts’ highlighted in teal, £100,000 in blue, and 10% in orange, all formatting preserved

Highlighted package name? ✅ Coloured price and discount? ✅ Not a single {{ }} left behind? ✅ A fully personalised commercial proposal, generated from a button press.


Practical Takeaways

  • PowerPoint (and Word) split text into “runs”. If a find-and-replace “isn’t working” on some words but not others, split runs are almost always the culprit. The same trap exists in Word documents.
  • Reconstruct the whole paragraph before searching — never match on individual runs.
  • When you write the result back, be surgical. Only touch the runs the placeholder occupies, so highlighted and coloured text keeps its styling.
  • Iterate the prompt, not the code. I never touched the generated Python by hand. Each time, I refined the plain-English rules and let the prompt regenerate the code. That’s the no-code-to-pro-code spectrum working for you.
  • Be specific in your prompt rules. Vague instructions (“replace the placeholders”) gave vague code. Spelling out the run-splitting behaviour and the formatting requirement is what produced robust code.

Final Thoughts

What I love about this is that the hard-won knowledge — the fact that PowerPoint shreds your text into runs — didn’t have to live in code I maintain. It lives in a prompt, in words I can read and tweak. Once I understood the underlying problem, fixing it was a case of describing the behaviour I wanted clearly enough for the model to generate the right code. That’s a really powerful pattern: you bring the domain insight, the AI brings the implementation.

If you’re building document-automation flows, give this a go — and the next time a placeholder won’t replace, you’ll know exactly where it’s hiding.


Enjoyed this? I share Power Platform, Copilot Studio and automation tips over on my YouTube channel — come and say hi: youtube.com/@DamoBird365