Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
microsoft avatar

Dv Solution

  • 42 installs
  • 184 repo stars
  • Updated July 28, 2026
  • microsoft/dataverse-skills

dv-solution is an agent skill for Dataverse solution create, export, import, promote, and validate lifecycle via PAC CLI and Python SDK.

About

The dv-solution skill manages Dataverse solution lifecycle including create, export, unpack, pack, import, and validate deployments across dev, test, and production environments. Publisher discovery queries existing non-Microsoft publishers via Python SDK before creating new ones because customization prefix is permanent on every component. Solution records are created with client.records.create rather than pac because no pac solution create command exists. PAC CLI handles export, unpack, pack, import, and add-solution-component operations while post-import validation uses the Python SDK. The skill forbids hardcoding the default new prefix, requires user confirmation for publisher choice, and enforces SDK over raw HTTP for publisher and solution record creation. Boundaries route schema work to dv-metadata, records to dv-data, queries to dv-query, and connection to dv-connect. Workflows cover version bumps, managed versus unmanaged exports, environment promotion, and validation scripts after import. Use when packaging customizations, deploying solutions to another environment, or promoting work between Dataverse environments.

  • Publisher discovery flow with permanent customization prefix rules.
  • SDK-based publisher and solution record creation with PAC for export import.
  • Post-import validation using Python SDK after PAC deployments.
  • Environment promotion workflows across dev test and production.
  • Boundaries to dv-metadata, dv-data, dv-query, and dv-connect skills.

Dv Solution by the numbers

  • 42 all-time installs (skills.sh)
  • +2 installs in the week ending Jun 21, 2026 (Skillselion tracking)
  • Ranked #145 of 257 Release Management skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

dv-solution capabilities & compatibility

Capabilities
publisher discovery and prefix confirmation · sdk solution record creation · pac export unpack pack import workflows · cross environment promotion and validation · managed versus unmanaged export guidance
Works with
azure
Use cases
ci cd · api development
From the docs

What dv-solution says it does

Create, export, unpack, pack, import, and validate Dataverse solutions via PAC CLI.
SKILL.md
npx skills add https://github.com/microsoft/dataverse-skills --skill dv-solution

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs42
repo stars184
Security audit3 / 3 scanners passed
Last updatedJuly 28, 2026
Repositorymicrosoft/dataverse-skills

How do I package Dataverse customizations and deploy them to another environment?

Manage Dataverse solution lifecycle with create, export, import, promote, and validate deployments across environments.

Who is it for?

Power Platform teams promoting managed or unmanaged solutions between Dataverse environments.

Skip if: Skip for schema authoring only, record CRUD, or initial workspace connection setup.

When should I use this skill?

User asks to export Dataverse solution, import to test prod, or promote customizations across environments.

What you get

Exported unpacked solution artifacts imported and validated in the target Dataverse environment.

Files

SKILL.mdMarkdownGitHub ↗

Skill: Solution

Create, export, unpack, pack, import, and validate Dataverse solutions via PAC CLI. Includes post-import validation using the Python SDK.

Skill boundaries

NeedUse instead
Create tables, columns, relationships, forms, viewsdv-metadata
Create, update, or delete data recordsdv-data
Query or read recordsdv-query
Connect to Dataverse / set up MCPdv-connect

---

Create a New Solution

Use the Python SDK for publisher and solution record creation — not raw HTTP. Publishers and solutions are standard Dataverse tables. client.records.create() and client.records.get() handle auth, pagination, and error handling automatically, avoiding the URL encoding, header boilerplate, and GUID-parsing bugs that raw urllib calls introduce.

Step 1: Find or Create the Publisher

Every solution belongs to a publisher. The publisher's customizationprefix (e.g., contoso, sa, lit) is prepended to every custom table, column, and relationship schema name. This prefix is effectively permanent — existing components keep their prefix forever, even if you change the publisher later.

Never use the default `new` prefix. It provides no organizational identity, risks naming collisions, and signals the developer did not follow best practices.

Discovery flow — always run this before creating a publisher:

import os, sys
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_client

# get_client sets a plugin attribution context on the User-Agent header.
# Do not modify the context value — it is a closed schema for server-side
# telemetry (app/skill/agent). Never include secrets or PII.
client = get_client("dv-solution")

# 1. Query for existing non-Microsoft publishers
pages = client.records.get(
    "publisher",
    filter="customizationprefix ne 'none' and uniquename ne 'MicrosoftCorporation' and uniquename ne 'Microsoftdynamic'",
    select=["publisherid", "uniquename", "friendlyname", "customizationprefix"],
    top=10,
)
publishers = [p for page in pages for p in page]

if publishers:
    # Show existing publishers and ask user which to use
    print("Existing publishers in this environment:")
    for p in publishers:
        print(f"  {p['uniquename']} (prefix: {p['customizationprefix']}_)")
    # ASK THE USER: "Which publisher should this solution use?"
    # Or: "Should I reuse '<name>' (prefix: <prefix>_)?"
    publisher_id = publishers[0]["publisherid"]  # after user confirms
else:
    # No custom publisher exists — ASK THE USER for prefix
    # "What publisher prefix should I use? (e.g., 'contoso', 'sa', 'lit' — 2-8 lowercase chars)"
    publisher_id = client.records.create("publisher", {
        "uniquename": "<publisheruniquename>",
        "friendlyname": "<Publisher Display Name>",
        "customizationprefix": "<prefix>",   # from user input, NOT 'new'
        "description": "<description>",
    })

Rules:

  • Always ask the user before creating a new publisher or choosing a prefix. Never hardcode a prefix.
  • The prefix must match any tables already created in the solution — you cannot mix prefixes.
  • One publisher can own many solutions. Reuse an existing publisher when possible.

Step 2: Create the Solution Record

Use the SDK to create the solution record (preferred over raw Web API):

import os, sys
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_client

# get_client sets a plugin attribution context on the User-Agent header.
# Do not modify the context value — it is a closed schema for server-side
# telemetry (app/skill/agent). Never include secrets or PII.
client = get_client("dv-solution")

# Create the solution record
solution_id = client.records.create("solution", {
    "uniquename": "<UniqueName>",
    "friendlyname": "<Display Name>",
    "version": "1.0.0.0",
    "publisherid@odata.bind": "/publishers(<publisher_guid>)",
})
print(f"Created solution: {solution_id}")

The required fields:

Table:  solution
Fields: uniquename    = "<UniqueName>"
        friendlyname  = "<Display Name>"
        version       = "1.0.0.0"
        publisherid   = <publisher GUID from step 1>
Note: There is no pac solution create command. PAC CLI handles export/import/pack/unpack, not solution record creation. Use the SDK or Web API to create the record.

Step 3: Add Components

Use pac solution add-solution-component to add tables, forms, views, and other components:

pac solution add-solution-component \
  --solutionUniqueName <UniqueName> \
  --component <ComponentSchemaName> \
  --componentType <TypeCode> \
  --environment <url>
Note: PAC CLI uses camelCase args here (--solutionUniqueName, --componentType), not kebab-case.

Common component type codes:

Type CodeComponent
1Entity (Table)
2Attribute (Column)
26View
60Form
61Web Resource
300Canvas App
371Connector

Repeat the command for each component you need to add.

Alternative: Auto-add via MSCRM.SolutionName Header

When creating metadata via the Web API, include the MSCRM.SolutionName header to auto-add components to the solution:

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json",
    "MSCRM.SolutionName": "<UniqueName>"
}

Important: After using this approach, verify components were added by listing them:

pac solution list-components --solutionUniqueName <UniqueName> --environment <url>

If the header was misspelled or the solution doesn't exist, components will be created in the default solution instead — silently. Always verify.

Find the Solution Name

Before exporting, confirm the exact unique name:

pac solution list --environment <url>

The UniqueName column is what you pass to other commands. Display names have spaces; unique names do not.

Pull: Export + Unpack

Confirm the target environment before exporting or importing. Run pac auth list + pac org who, show the output to the user, and confirm it matches the intended environment. Developers work across multiple environments — do not assume.

Export the solution as unmanaged (source of truth):

pac solution export \
  --name <UniqueName> \
  --path ./solutions/<UniqueName>.zip \
  --managed false \
  --environment <url>

Unpack into editable source files:

pac solution unpack \
  --zipfile ./solutions/<UniqueName>.zip \
  --folder ./solutions/<UniqueName> \
  --packagetype Unmanaged

Delete the zip — the unpacked folder is the source:

rm ./solutions/<UniqueName>.zip

Commit:

git add ./solutions/<UniqueName>
git commit -m "chore: pull <UniqueName> baseline"
git push

Push: Pack + Import

Pack the source files back into a zip:

pac solution pack \
  --zipfile ./solutions/<UniqueName>.zip \
  --folder ./solutions/<UniqueName> \
  --packagetype Unmanaged

Import (async recommended for large solutions):

pac solution import \
  --path ./solutions/<UniqueName>.zip \
  --environment <url> \
  --async \
  --activate-plugins

Poll Import Status

After async import, check the job:

pac solution list --environment <url>

Post-Import Validation

After importing a solution, verify that components are live. Use the Python SDK to check directly — no external scripts needed.

Check a table exists

info = client.tables.get("<logical_name>")
if info:
    print(f"[PASS] Table '{info['LogicalName']}' exists")
else:
    print(f"[FAIL] Table '<logical_name>' not found")

Check a form is published

pages = client.records.get(
    "systemform",
    filter="objecttypecode eq '<entity>' and type eq <form_type_code>",
    select=["name", "formid"],
    top=5,
)
forms = [f for page in pages for f in page]
# Form type codes: 2 = main, 7 = quick create

Check a view exists

pages = client.records.get(
    "savedquery",
    filter="returnedtypecode eq '<entity>'",
    select=["name", "savedqueryid", "statuscode"],
    top=10,
)
views = [v for page in pages for v in page]

Check a user's role assignment (Web API only)

N:N $expand (like systemuserroles_association) is not supported by the SDK. This is one of the few cases where raw Web API is required:

# Web API required — SDK does not support N:N $expand
import os, sys, urllib.request, json
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_token, get_plugin_headers, load_env  # get_token + get_plugin_headers — SDK can't do this

load_env()
env = os.environ["DATAVERSE_URL"].rstrip("/")
token = get_token()
url = f"{env}/api/data/v9.2/systemusers?$filter=internalemailaddress eq '<email>'&$select=fullname&$expand=systemuserroles_association($select=name)&$top=1"
headers = get_plugin_headers("dv-solution", token)
headers.update({"OData-MaxVersion": "4.0", "OData-Version": "4.0", "Accept": "application/json"})
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req) as resp:
    users = json.loads(resp.read()).get("value", [])
if users:
    roles = [r["name"] for r in users[0].get("systemuserroles_association", [])]
    print(f"Roles: {', '.join(roles)}")

Check import errors

pages = client.records.get(
    "importjob",
    select=["importjobid", "solutionname", "startedon", "completedon", "progress"],
    orderby=["startedon desc"],
    top=5,
)
jobs = [j for page in pages for j in page]

For detailed error history, also query msdyn_solutionhistory:

pages = client.records.get(
    "msdyn_solutionhistory",
    filter="msdyn_status eq 1",  # 1 = failed
    select=["msdyn_name", "msdyn_starttime", "msdyn_exceptionmessage"],
    orderby=["msdyn_starttime desc"],
    top=5,
)

Validation error reference

ErrorCauseFix
Table not found after importComponent not in solutionAdd via pac solution add-solution-component
Form check fails immediatelyPublishing is asyncWait 30 seconds and retry
Role not assignedUser not provisionedAssign the role via pac admin assign-user or the Power Platform Admin Center
Import job at 0%Import still runningPoll again in 60 seconds

Notes

  • Always use --managed false / --packagetype Unmanaged for the development solution. Managed packages are for deployment to downstream environments (test, prod).
  • --activate-plugins ensures any registered plugins in the solution are activated on import.
  • If you see "solution already exists" errors, use --import-mode ForceUpgrade to overwrite.
  • Large solutions (Sales, Customer Service) can take 10–20 minutes to import. Be patient and poll rather than re-importing.
  • All validation queries above require auth. Use scripts/auth.py for credential/token acquisition. See dv-query for SDK query patterns and dv-data for write patterns.

Related skills

FAQ

What does dv-solution produce?

Packaged solution artifacts exported via PAC, imported to target environments, and validated with SDK checks.

When should I use dv-solution?

When packaging, exporting, importing, or promoting Dataverse solutions between environments.

Is dv-solution safe to install?

Review the Security Audits panel on this page before installing in production.

Release Managementintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.