Copilot Studio 14 min read

Automating Application Provisioning with Copilot Studio’s New Agent Builder

Automating Application Provisioning with Copilot Studio’s New Agent Builder
A hands-on, step-by-step guide to building a Developer Agent in Copilot Studio that provisions SharePoint backends and generates Canvas App YAML UI — from manual artifact generation to zero-touch deployment.

The role of AI in enterprise development is shifting rapidly from conversational assistance to direct task execution. With the new Agent Builder in Microsoft Copilot Studio (currently in Preview), developers can configure agents that act as active contributors to the software development lifecycle — not just describing what to build, but building it.

Instead of producing documentation, we can configure a Developer Agent that generates consistent, deployable Power Platform solutions, handling both the backend data schema (SharePoint lists) and the frontend Canvas App UI (Power Apps YAML).

This is a practical, end-to-end walkthrough. We start with an agent that generates deployable artifacts you run by hand, then evolve it into an agent that executes the provisioning itself for true zero-touch deployment.

What You’ll Build

By the end you’ll have a single agent that can take a prompt like “Build an Asset Management System” and:

  • Phase 1 (manual): generate a ready-to-run PnP PowerShell script for the SharePoint backend and Power Apps YAML for the frontend screens.
  • Phase 2 (automated): call a Power Automate Tool that provisions the SharePoint lists and columns directly — no copy/paste required.

Prerequisites — check these before you start: - A Copilot Studio license (or trial) with Preview features enabled for the environment. - A Power Platform environment where you can author agents and flows. - A SharePoint site where your account has at least Member (Edit) permission to create lists.

  • For Phase 1 backend: the PnP.PowerShell module installed (Install-Module PnP.PowerShell) and an Entra app registration with a Client ID. Since the shared PnP Management Shell app was retired, Connect-PnPOnline -Interactive now requires your own -ClientId. You can register one quickly with Register-PnPEntraIDAppForInteractiveLogin. - For Phase 2: permission to create a Power Automate flow that uses the SharePoint connector.

1. Initializing the Developer Agent

The journey begins in the Copilot Studio preview environment. When you create a new agent, the foundational step is defining its persona and core instructions. For this use case we define an AI Canvas App Builder Agent whose explicit goal is to generate deployable Power Platform solutions.

Paste this into the agent’s Instructions field as a starting point:

Code
You are an AI Canvas App Builder Agent. Your job is to generate deployable
Power Platform solutions.

When a user asks you to build an app:
1. Design the backend as SharePoint lists (list names, columns, and column types).
2. Design the frontend as Power Apps Canvas App YAML (screens, controls, and
   Power Fx formulas).
3. Always confirm the list/column design with the user before producing the
   final artifacts.

Use clear, consistent naming. Prefer Choice columns over free text where a fixed
set of values makes sense.
🧠

Model selection matters for structured output. When the agent is producing strict JSON, REST payloads, and indentation-sensitive YAML, lighter models tend to drift on syntax. Switch the agent’s foundational model from the default to a higher-reasoning model (in my testing, Claude Opus 4.7 held YAML indentation and JSON schemas together far more reliably than the lighter default). You’ll find this under the agent’s Settings → Generative AI / Model options. Available models evolve in Preview, so pick the strongest reasoning option offered to your environment.

2. Phase 1: Generating Artifacts You Deploy by Hand

Phase 1 Manual Artifact Generation

In the first iteration the agent produces deployable artifacts — a script and a YAML file — that you execute. The agent isn’t connecting to anything yet; it’s generating code from its instructions.

💡

“Skill” vs “Tool” — the distinction that drives this whole article. In this phase the agent’s capabilities are instruction-driven: it generates text (code) based purely on its prompt and knowledge. It does not touch your tenant. In Phase 2, we attach a real Tool — a connected action (a Power Automate flow) that the agent actually runs. Same agent, two very different modes: describe the work vs. do the work.

We split Phase 1 into two capabilities: a backend generator and a frontend generator.

2.1 The Backend Generator (PnP PowerShell)

Add an instruction block that tells the agent to emit a PnP PowerShell script when the user wants a SharePoint backend:

  • Trigger: the user asks to build an app with a SharePoint backend.
  • Behavior: produce a script that connects to a target site, creates the lists, defines columns (Choice, Text, Number, etc.), and injects a few sample rows.

The single most effective thing you can do here is show the agent the exact syntax you expect by pasting a reference snippet into the instructions. Here’s a known-good PnP template to anchor it:

Code
# 1. Connect — PnP PowerShell now requires YOUR OWN Entra app Client ID.
#    (Run Register-PnPEntraIDAppForInteractiveLogin once to create it.)
Connect-PnPOnline -Url "https://contoso.sharepoint.com/sites/AssetMgmt" `
  -Interactive -ClientId "<your-entra-app-client-id>"

# 2. Create the list
New-PnPList -Title "Assets" -Template GenericList -OnQuickLaunch

# 3. Add columns
Add-PnPField -List "Assets" -DisplayName "Asset Tag" `
  -InternalName "AssetTag" -Type Text -AddToDefaultView
Add-PnPField -List "Assets" -DisplayName "Category" `
  -InternalName "Category" -Type Choice `
  -Choices "Laptop","Monitor","Phone","Peripheral" -AddToDefaultView
Add-PnPField -List "Assets" -DisplayName "Purchase Cost" `
  -InternalName "PurchaseCost" -Type Number -AddToDefaultView

# 4. Inject sample data
Add-PnPListItem -List "Assets" -Values @{
  "Title"        = "MBP-001"
  "AssetTag"     = "AT-1001"
  "Category"     = "Laptop"
  "PurchaseCost" = 2400
}
💡

Iterative refinement beats one big prompt. Don’t expect perfect output on the first try. Generate a script, run it, and feed the agent corrections (“the Title field already exists, don’t recreate it”; “use -AddToDefaultView so columns show up”). A handful of examples and formatting rules in the instructions dramatically improves accuracy.

2.2 The Frontend Generator (Power Apps YAML)

Instead of the drag-and-drop maker studio, we have the agent generate the UI as Power Apps YAML — the same source format Power Apps uses on the clipboard when you copy a control, and in pac canvas source files.

  • Trigger: the user requests a Canvas App frontend.
  • Behavior: generate YAML representing screens (Home, New Request, Admin Dashboard) with controls and embedded Power Fx.

A representative control block looks like this (the format is indentation-sensitive — this is exactly where a stronger model earns its keep):

Code
- HomeScreen:
    Control: screen
    Children:
      - TitleLabel:
          Control: text
          Properties:
            Text: ="Asset Management"
            X: =40
            Y: =32
            Size: =24
            FontWeight: =FontWeight.Semibold
      - AssetGallery:
          Control: gallery
          Properties:
            Items: =Assets
            X: =40
            Y: =96
            Width: =Parent.Width - 80
            Height: =Parent.Height - 140
      - NewAssetButton:
          Control: classic/button
          Properties:
            Text: ="+ New Asset"
            OnSelect: =Navigate(NewRequestScreen, ScreenTransition.Cover)

2.3 Deploying the Phase 1 Output

Backend:

  1. Copy the generated script into a .ps1 file (or run it directly).
  2. Connect with the SharePoint Online Management Shell / PnP PowerShell — remember the -ClientId requirement above.
  3. Run the script to provision the lists, columns, and sample data.

Frontend:

  1. Create a blank Canvas app and add your newly created SharePoint lists as data sources.
  2. In Power Apps Studio, use the control copy/paste (YAML) path: select a screen/control, then paste the agent’s YAML to materialize the controls.
  3. If you see minor reference errors (e.g., a control points at a screen that doesn’t exist yet), fix them in the formula bar — they resolve in seconds once all screens are pasted.
⚠️

Reality check on YAML paste: full multi-screen reconstruction from YAML is still a Preview/evolving experience and is sensitive to exact indentation and control schema. Treat the agent’s YAML as a strong scaffold you finish in Studio, not a guaranteed one-shot import. Paste screen by screen and resolve reference errors as you go.

3. Phase 2: Zero-Touch Provisioning with a Tool

Phase 2 Automated Zero-Touch Provisioning

Copy/paste is a huge time-saver, but the real win is when the agent executes the provisioning itself. To do that we replace the generated PowerShell with a Tool — a Power Automate flow the agent calls directly.

Step A: Build the “List Generator” flow

Create a Power Automate flow that does the heavy lifting of SharePoint provisioning.

Trigger: use the “When an agent calls the flow” trigger (the Copilot/Power Apps V2-style trigger) and define two inputs:

InputTypeDescription (this text is what the agent reads to map parameters)
SiteUrlTextThe full URL of the target SharePoint site, e.g. https://contoso.sharepoint.com/sites/AssetMgmt.
ListDefinitionTextA JSON array of lists to create. Each item has listName and a columns array of { name, type, choices? }.

Parse the payload. Add a Parse JSON action on ListDefinition with this schema:

Code
{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "listName": { "type": "string" },
      "columns": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "name": { "type": "string" },
            "type": { "type": "string" },
            "choices": { "type": "array", "items": { "type": "string" } }
          },
          "required": ["name", "type"]
        }
      }
    },
    "required": ["listName", "columns"]
  }
}

Create each list. Add an Apply to each over the parsed array. Inside it, add Send an HTTP request to SharePoint:

  • Site Address: SiteUrl
  • Method: POST
  • Uri: _api/web/lists
  • Headers: Accept: application/json;odata=nometadata and Content-Type: application/json;odata=verbose
  • Body:
Code
{
  "__metadata": { "type": "SP.List" },
  "BaseTemplate": 100,
  "Title": "@{items('Apply_to_each')?['listName']}"
}

Create each column. Add a nested Apply to each over columns, with another Send an HTTP request to SharePoint:

  • Uri: _api/web/lists/getbytitle('@{items('Apply_to_each')?['listName']}')/fields
  • Body (Text column shown; set FieldTypeKind per the table below):
Code
{
  "__metadata": { "type": "SP.Field" },
  "FieldTypeKind": 2,
  "Title": "@{items('Apply_to_each_2')?['name']}"
}
Column typeFieldTypeKind
Text2
Multi-line text (Note)3
Number9
DateTime4
Boolean (Yes/No)8
Choice6
⚠️

Choice columns need a different endpoint. The simple /fields POST works cleanly for Text/Number/DateTime. For Choice (and Lookup) columns, use createfieldasxml, which accepts a full field schema in one shot:

Code
{
  "parameters": {
    "__metadata": { "type": "SP.XmlSchemaFieldCreationInformation" },
    "SchemaXml": "<Field Type='Choice' DisplayName='Category'><CHOICES><CHOICE>Laptop</CHOICE><CHOICE>Monitor</CHOICE><CHOICE>Phone</CHOICE></CHOICES></Field>",
    "Options": 12
  }
}

POST it to _api/web/lists/getbytitle('Assets')/fields/createfieldasxml. Branch on columns/type with a Condition or Switch so Choice columns take this path and the rest take the simple /fields path.

Return a result to the agent. Finish with a Respond to the agent action returning a short status string (e.g. “Created 2 lists with 5 columns.”). Without this, the agent can’t confirm success to the user.

Step B: Rewrite the backend instructions

With the Tool attached to the agent, the backend is no longer about PowerShell — it’s about producing a strict data payload and invoking the Tool. Update the backend instruction block:

Code
When building the SharePoint backend, do NOT generate a PnP script.
Instead:
1. Produce a List Definition as a JSON array. Each item: { listName, columns: [ { name, type, choices? } ] }.
2. Use only these column types: Text, Number, DateTime, Boolean, Choice.
3. Ask the user for the target SharePoint Site URL.
4. Then call the "List Generator" tool, passing SiteUrl and the JSON as ListDefinition.
Before calling the tool, validate that the JSON is well-formed.

The agent should emit a payload like this:

Code
[
  {
    "listName": "Assets",
    "columns": [
      { "name": "AssetTag", "type": "Text" },
      {
        "name": "Category",
        "type": "Choice",
        "choices": ["Laptop", "Monitor", "Phone"]
      },
      { "name": "PurchaseCost", "type": "Number" }
    ]
  },
  {
    "listName": "AssignmentLog",
    "columns": [
      { "name": "Employee", "type": "Text" },
      { "name": "AssignedDate", "type": "DateTime" }
    ]
  }
]

Step C: Test it (zero-touch)

Prompt the agent: “Build an Asset Management System.” Here’s the flow you should observe:

  1. The agent confirms the list/column design, then asks you for the target SharePoint URL.
  2. On receiving the URL, it generates the JSON payload internally and maps it to the Tool’s SiteUrl and ListDefinition inputs.
  3. It triggers the List Generator Tool.
  4. The flow runs in the background and spins up the lists and columns automatically — then reports back the status string you returned in Step A.
💡

If the agent skips asking for the URL, make SiteUrl a required input and add an explicit line to the instructions (“Always ask for the SharePoint Site URL before calling the tool”). Required inputs + an explicit instruction is the reliable combination.

4. Troubleshooting

SymptomCauseFix
Flow returns 403 / Access deniedThe flow connection account lacks rights on the siteReconnect the SharePoint action with an account that has Edit/Member on the target site
Choice column missing after the runChoice can’t be created via the simple /fields POSTUse the createfieldasxml branch shown above
Agent doesn’t call the toolInput descriptions are vague, or model driftedTighten the input descriptions, mark inputs required, and prefer a higher-reasoning model
Agent emits malformed JSONLighter model or over-long payloadAdd a “validate JSON before calling the tool” instruction; switch to a stronger model
Duplicate tool versions appear after publishingKnown Copilot Studio Preview quirkCosmetic only — it doesn’t affect execution of the latest iteration. Proceed normally
YAML paste shows reference errorsControls reference screens not pasted yetPaste all screens, then resolve in the formula bar

The Ultimate Value Proposition

By configuring a Developer Agent with this hybrid approach — UI generation (YAML) plus automated infrastructure deployment (a Workflow Tool) — organizations can enforce strict design consistency and drastically cut repetitive setup. The agent stops being a conversational chatbot and code-assistant and becomes a functional, task-completing member of the engineering team.

Start in Phase 1 to get comfortable and to keep a human in the loop, then graduate the backend to the Phase 2 Tool once you trust the output. The frontend can stay in YAML-scaffold mode for as long as the paste experience remains in Preview — and you can fold it into a Tool the same way the moment a supported generation API is available.

Discussion

Loading...