- 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:
- Click + Add an app → search
PowerPlatform-ALM-SPN→ Add - Business unit: accept the default (the org root)
- Security roles: pencil icon → System Administrator → Save
- 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 connection → Power Platform → Application 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
- Make your change in DEV (maker portal) — add a column, edit the app, whatever
- Publish all customizations in DEV
- Bump the solution version in DEV (Solutions → ALM-TEST → ⋮ → Settings → e.g.
1.0.0.0→1.0.0.1) - Run export-from-dev → pulls the change out of Dataverse and commits the XML to your repo
- 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.