Power Platform: export a Solution with an Azure DevOps Pipeline

Why?

In the previous post Power Platform: connect an Azure DevOps Pipeline ยป Knowhere365, I showed how to connect an Azure DevOps Pipeline to the Power Platform. Now we are going to let the Pipeline export a Power Platform Solution.

What?

In this post, I am going to let the Azure DevOps Pipeline export a Power Platform Solution to our Git Repo.

How?

Most blog posts on this topic will keep it “simple” and only use Variables defined in the Pipeline itself: see Define variables – Azure Pipelines | Microsoft Docs. I want to be prepared for multiple Pipelines using the same Variables over and over again… To support this I will use Variable Groups stored in the Azure DevOps Project Libary: see Variable groups for Azure Pipelines – Azure Pipelines | Microsoft Docs.

1) Create a Variable Group for our DEV Environment. I named this group after the the environment itself to be consistent:

For now, I only know three variables so I added them already:

2) Because I am such a control freak, I want to save all variants of the Power Platform Solution.
This means I want to save the Unmanaged Solution as a .zip file. I also want the Managed Solution saved as a .zip file. And I want to save the Unmanaged Solution unpacked as individual files so all the source code files are saved separately. Last but not least, I want the Pipeline to save all these variants to our Git Repo and make sure that Git delivers nice versioning on all these files. An important aspect to verify, is if the Git Repo is configured to allow the Pipeline Machine to commit files. Select Manage repositories of the desired Git Repo:

In the Security tab we need to make sure that the Build Service of our Azure DevOps Project is allowed to:
– Bypass policies when pushing
– Contribute

In a previous post, I already mentioned that any Azure DevOps Project could host a Pipeline. Even when yoy want to save to a Git Repo of another Azure DevOps Project. For that scenario, this will also be the place to add the Build Service of that Azure DevOps Project and give it the correct permissions on the specific Git Repo ๐Ÿ”“.

3) Below an example of a .yml Pipline that uses the Variable Group and will do all these Tasks (for details see Build tool tasks – Power Platform | Microsoft Docs):

trigger: none
pool:
  vmImage: windows-latest

variables:
- group: 'insbadev01'

steps:
# Prepare #
  - checkout: self
    persistCredentials: true
  - task: PowerPlatformToolInstaller@0 #Always Install this when using PowerPlatformBuiltTools on machine
    displayName: Prepare - Install PP Tool
    inputs:
      DefaultVersion: true

# Solutions logic #
  - task: PowerPlatformPublishCustomizations@0 #Publish Environment Customizations
    displayName: Solutions - Publish customizations
    inputs:
      authenticationType: 'PowerPlatformSPN'
      PowerPlatformSPN: 'insbadev01connection'
  - task: PowerPlatformExportSolution@0 #Export Unmanaged Solution to machine
    displayName: Solutions - UnmSol export zip locally
    inputs:
      authenticationType: 'PowerPlatformSPN'
      PowerPlatformSPN: 'insbadev01connection'
      SolutionName: '$(PowerPlatformSolution01)'
      SolutionOutputFile: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)UM.zip'
      AsyncOperation: true
      MaxAsyncWaitTime: '60'
      ExportAutoNumberingSettings: true
  - task: PowerShell@2  #Push Unmanaged Solution zip file to Git Repo 
    displayName: Solutions - UnmSol zip to repo
    inputs:
      targetType: 'inline'
      script: |      
        # Write your PowerShell commands here.        
        ls ${env:GitDirectoryExportedSolutions}
        git config --global user.email ${env:gituser} 
        git config --global user.name ${env:gituser}
        git checkout main
        git add ${env:GitDirectoryExportedSolutions}
        git commit -am "Added Solution Export ${env:PowerPlatformSolution01}UM as zip"
        git push origin main
  - task: PowerPlatformUnpackSolution@0 #Unpack Unmanaged Solution zip file
    displayName: Solutions - UnmSol export folders locally
    inputs:
      SolutionInputFile: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)UM.zip'
      SolutionTargetFolder: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)Unmanaged'
  - task: PowerShell@2  #Push unpacked Unmanaged Solution files to Git Repo
    displayName: Solutions - UnmSol folders to repo    
    inputs:
      targetType: 'inline'
      script: |      
        # Write your PowerShell commands here.        
        ls ${env:GitDirectoryExportedSolutions}
        git config --global user.email ${env:gituser} 
        git config --global user.name ${env:gituser}
        git checkout main
        git add ${env:GitDirectoryExportedSolutions}\${env:PowerPlatformSolution01}Unmanaged
        git commit -am "Added Solution Export ${env:PowerPlatformSolution01} unpacked"
        git push origin main
  - task: PowerPlatformExportSolution@0  #Push solution Managed zip file to Git Repo
    displayName: Solutions - ManSol export zip locally
    inputs:
      authenticationType: 'PowerPlatformSPN'
      PowerPlatformSPN: 'insbadev01connection'
      SolutionName: '$(PowerPlatformSolution01)'
      SolutionOutputFile: '$(GitDirectoryExportedSolutions)\$(PowerPlatformSolution01)M.zip'
      Managed: true
      AsyncOperation: true
      MaxAsyncWaitTime: '60'
      ExportAutoNumberingSettings: true
  - task: PowerShell@2  #Push solution Managed zip file to repo
    displayName: Solutions - ManSol zip to repo
    inputs:
      targetType: 'inline'
      script: |      
        # Write your PowerShell commands here.        
        ls ${env:GitDirectoryExportedSolutions}
        git config --global user.email ${env:gituser} 
        git config --global user.name ${env:gituser}
        git checkout main
        git add ${env:GitDirectoryExportedSolutions}
        git commit -am "Added Solution Export ${env:PowerPlatformSolution01}M as zip"
        git push origin main

The hardcore .yml Pipeline builders may have noticed one Variable defined on Pipeline level: gituser. I have chosen for this approach so a person performing a manual run can change it to their own e-mail address. This will result in the Git history, showing that person being the one committing the files.

Because I am using a Variable Group, I needed to give the Pipeline permissions for the first run:

This should result in a nice successful Job Run:

And off course a nice Git Repo storing the Solution files:

Here we are! A Git Repo containing the three options to record our Power Platform Solution as source code worthy files. An Unmanaged Solution as a .zip file, a Managed Solution as a .zip file and an Unmanaged Solution unpacked. With version history containing a new version every time the Pipeline runs ๐Ÿ˜Ž

8 thoughts on “Power Platform: export a Solution with an Azure DevOps Pipeline

  1. Will the managed and unmanaged files be over written each time theres a change or will it keep the files for each version i.e previous files and new file so in your example there will be a four files in the next build when thereโ€™s a change?

    1. Hi Shomari,
      In this example there will be three files as output:
      “An Unmanaged Solution as a .zip file, a Managed Solution as a .zip file and an Unmanaged Solution unpacked.”

      With every Build run of a Pipeline new versions of alle files will be saved giving us a history of changes per file. Especially the unpacked versions are very useful because this will actually show the changes on the lowest level but only in the files that were changed. This gives you a very nice delta between versions (commits).
      The zip files off course only show one big file and not what was actually changed within the Solution…

      1. Thanks for the speedy reply. I will be definitely be applying your method in the blogs and I just have some more questions which out of the three file which one will I deploy to production. It should be the manรจges zip file but I just want to double check

  2. hi, it’s very nice and detailed article. I just have a question, right now there is an option to give only one solution name for export, how do we handle if there is a need for multiple solution export in a single pipeline.

    Is there any way to provide json file as an input for looping through?

Leave a comment