ALM DOCUMENTATION (Power Platform Solution) Dev -> UAT

  1. Firstly created two environments for one is dev and one is for uat
  • DEV: https://mcm-m-dev.crm.dynamics.com/
  • UAT: https://mcm-m-uat.crm.dynamics.com/

Note: Verify you’re System Administrator in each: Environment → Settings → Users + permissions → Users → your name → confirm System Administrator appears under Direct Assigned Roles.

2. In mcm-m-dev : Created one solution and in that i have added one table and in that table added few fileds… and did published…in the same solution added one model driven app and added table which we created before

Entra app registration

Go to Azure Portal And Entra Id and register for new app copy client id and tenant id from the app which u created

portal.azure.com → Microsoft Entra ID → App registrations → + New registration

  • Name: PowerPlatform-ALM-SPN
  • Supported account types: Accounts in this organizational directory only (Single tenant)
  • Redirect URI: leave blank
  • Register

Application (client) ID: 9422e4cb-df91-4f34-abd6-005c976ba81f

Directory (tenant) ID: 6ab18296-4ab9-4e72-a085-b3ac41a86d0c

Record the Application (client) ID from the Overview page.

After Creating App registration go to certificates and secrets –> create new client secret

Value: YY38Q~WtrlYUmQMzyV0_XxRnAp3IhKpWv6vc5bn5 | Secret ID: 74941cbb-c8de-4693-8000-f3b74f53b67c

Part 4 — Register the app as an application user (both environments)

Repeat this twice — once for MCM-DEV, once for MCM-UAT. Missing either one breaks the corresponding pipeline stage.

Admin center → Environments → MCM-DEV → Settings → Users + permissions → Application users+ New app user:

  1. Click + Add an app → search PowerPlatform-ALM-SPN → Add
  2. Business unit: accept the default (the org root)
  3. Security roles: pencil icon → System Administrator → Save
  4. Create

Part 5 — Azure DevOps setup

5.1 Project and repo

dev.azure.com/shyamsundhar-dev+ New project:

  • Name: MemberCaseManagement
  • Visibility: Private
  • Version control: Git

Repos → Initialize the main branch with a README.

Extension

Organization settings → Extensions → confirm Power Platform Build Tools is installed. If you removed it: Browse marketplace → search → install.

Service connections

Connection 1 — DEV

Project settings → Service connections → New service connectionPower PlatformApplication ID and Secret.

Connection 1 — UAT

Same, but the MCM-UAT URL and name it PowerPlatform-UAT.

Repo permissions for the export pipeline

The export pipeline commits source back to the repo, so the build identity needs write access.

Project settings → Repos → Repositories → MemberCaseManagement → Security → find MemberCaseManagement Build Service (shyamsundhar-dev) → set Contribute to Allow.

Part 6 — Export pipeline (DEV → repo)

Pipelines → New pipeline → Azure Repos Git → MemberCaseManagement → Starter pipeline. Replace everything with:

name: export-from-dev

trigger: none

pool:
  vmImage: windows-latest

variables:
  SolutionName: MemberCaseManagement

steps:
- checkout: self
  persistCredentials: true

- task: PowerPlatformToolInstaller@2
  displayName: 'Install Power Platform Build Tools'

- task: PowerPlatformPublishCustomizations@2
  displayName: 'Publish customizations in DEV'
  inputs:
    authenticationType: PowerPlatformSPN
    PowerPlatformSPN: PowerPlatform-DEV

- task: PowerPlatformExportSolution@2
  displayName: 'Export unmanaged'
  inputs:
    authenticationType: PowerPlatformSPN
    PowerPlatformSPN: PowerPlatform-DEV
    SolutionName: $(SolutionName)
    SolutionOutputFile: $(Build.ArtifactStagingDirectory)\$(SolutionName).zip

- task: PowerPlatformExportSolution@2
  displayName: 'Export managed'
  inputs:
    authenticationType: PowerPlatformSPN
    PowerPlatformSPN: PowerPlatform-DEV
    SolutionName: $(SolutionName)
    SolutionOutputFile: $(Build.ArtifactStagingDirectory)\$(SolutionName)_managed.zip
    Managed: true

- task: PowerPlatformUnpackSolution@2
  displayName: 'Unpack to source'
  inputs:
    SolutionInputFile: $(Build.ArtifactStagingDirectory)\$(SolutionName).zip
    SolutionTargetFolder: $(Build.SourcesDirectory)\solutions\$(SolutionName)
    SolutionType: Both

- script: |
    git config user.email "build@shyamsundhar-dev"
    git config user.name "Azure DevOps Build"
    git checkout -B main
    git add --all
    git diff --quiet --cached || git commit -m "Export $(SolutionName) from DEV [skip ci]"
    git push origin main
  displayName: 'Commit solution source to repo'

Save and run.

What this does. Exports the solution twice (unmanaged and managed), then unpacks the unmanaged zip into hundreds of small XML files and commits them. That unpacked form is the point — it makes solution changes diffable and reviewable in pull requests, which is why real teams do it this way instead of committing a binary zip.

Expected result: a solutions/MemberCaseManagement/ folder appears in your repo.

Part 7 — Deploy pipeline (repo → UAT)

Pipelines → New pipeline → same repo → Starter pipeline. Name the file deploy-to-uat.yml:

name: deploy-to-uat

trigger: none

pool:
  vmImage: windows-latest

variables:
  SolutionName: MemberCaseManagement

steps:
- checkout: self

- task: PowerPlatformToolInstaller@2
  displayName: 'Install Power Platform Build Tools'

- task: PowerPlatformPackSolution@2
  displayName: 'Pack managed solution'
  inputs:
    SolutionSourceFolder: $(Build.SourcesDirectory)\solutions\$(SolutionName)
    SolutionOutputFile: $(Build.ArtifactStagingDirectory)\$(SolutionName)_managed.zip
    SolutionType: Managed

- task: PowerPlatformImportSolution@2
  displayName: 'Import to UAT'
  inputs:
    authenticationType: PowerPlatformSPN
    PowerPlatformSPN: PowerPlatform-UAT
    SolutionInputFile: $(Build.ArtifactStagingDirectory)\$(SolutionName)_managed.zip
    PublishWorkflows: true
    OverwriteUnmanagedCustomizations: false
    AsyncOperation: true
    MaxAsyncWaitTime: 60

- task: PowerPlatformPublishCustomizations@2
  displayName: 'Publish in UAT'
  inputs:
    authenticationType: PowerPlatformSPN
    PowerPlatformSPN: PowerPlatform-UAT

Run it after the export pipeline has committed source.

Why managed into UAT. Managed solutions are locked against direct editing in the target and can be cleanly uninstalled. Unmanaged imports permanently merge into the target and cannot be removed. Every real project ships managed downstream and keeps unmanaged only in DEV. Interviewers ask about this.

The cycle

  1. Make your change in DEV (maker portal) — add a column, edit the app, whatever
  2. Publish all customizations in DEV
  3. Bump the solution version in DEV (Solutions → ALM-TEST → ⋮ → Settings → e.g. 1.0.0.01.0.0.1)
  4. Run export-from-dev → pulls the change out of Dataverse and commits the XML to your repo
  5. Run deploy-to-uat → packs that XML as managed and imports it

Export always runs first. Deploy just reads whatever is currently in the repo, so running it alone would redeploy the previous state.

Why export isn’t automatic: Dataverse has no “commit” event. Nothing tells DevOps you changed something in the maker portal, so a human has to say “capture DEV now.” That’s true in real projects too.

Leave a Comment