Scripts/ExportSolution.ps1
# ExportSolution.ps1 function Get-DataverseSolution { Param( [string] [Parameter(Mandatory = $true)] $StartPath, [string] [Parameter(Mandatory = $true)] $SolutionName ) try { ######################## EXPORT SOLUTION ######################## # If patch version numbers can change, get existing values if ($global:devops_projectFile.IncrementLatestPatchOnExport -eq "True") { # Get current solution versions in files before updating them try { $versionsFile = Get-Content -Path $global:devops_projectLocation\$global:devops_SolutionName\$global:devops_SolutionName.version -ErrorAction SilentlyContinue | ConvertFrom-Json # Sort by version $existingPatchVersions = $versionsFile | Sort-Object { [version]$_.Version } } catch { #Legacy Solution Packaging Support $versionsFile = Get-Content -Path $PipelinePath\$SolutionFolder\$versionFile $existingPatchVersions = @([ordered]@{SolutionName = $package.SolutionName; Version = $versionsFile ; }) } } # Update version file Set-DataverseSolutionVersion # Delete any files in old formats / file structures that still exist from Microsoft.PowerPlatform.DevOps Remove-Item (Join-Path $StartPath "\dataverse_$SolutionName") -Force -Recurse -ErrorAction Ignore Remove-Item (Join-Path $StartPath "\dataverse_*patch*") -Force -Recurse -ErrorAction Ignore Remove-Item (Join-Path $StartPath "\pac_$SolutionName") -Force -Recurse -ErrorAction Ignore Remove-Item (Join-Path $StartPath "\pac_*patch*") -Force -Recurse -ErrorAction Ignore $patchFilesFolderPath = (Join-Path $StartPath "Patches\") $deployFilesFolderPath = (Join-Path $StartPath "Deploy\") $patchSolutionNames = @() # If there are no patches if (!$PatchQuery.CrmRecords) { # Delete any patch files Remove-Item $patchFilesFolderPath -Force -Recurse -ErrorAction Ignore Remove-Item $deployFilesFolderPath -Force -Recurse -ErrorAction Ignore # Export base solution Export-SolutionAndUnpack "$SolutionName" } else { # Export Patches # If project config says to increment latest patch if ($global:devops_projectFile.IncrementLatestPatchOnExport -eq "True") { Write-Host "Exporting all patches with changed version numbers" $patchCount = $PatchQuery.CrmRecords.Count $iterator = 1 foreach ($PatchSolution in $PatchQuery.CrmRecords) { $patchSolutionNames += $PatchSolution.uniquename $existingPatch = $existingPatchVersions | Where-Object { $PatchSolution.uniquename -eq $_.SolutionName } # If version number in CRM is different to existing file if ([version]$existingPatch[0].Version -eq [version]$PatchSolution.version) { Write-Host "Skipping patch $iterator of $patchCount due to unchanged version number: $($PatchSolution.uniquename)" } else { Write-Host "Exporting patch $iterator of $patchCount" # Remove the existing files for the patch Remove-Item -Path (Join-Path $deployFilesFolderPath "$($PatchSolution.uniquename).zip") -Force -ErrorAction SilentlyContinue Remove-Item -Path (Join-Path $deployFilesFolderPath "$($PatchSolution.uniquename)_managed.zip") -Force -ErrorAction SilentlyContinue Remove-Item -Path (Join-Path $patchFilesFolderPath $($PatchSolution.uniquename)) -Recurse -Force -ErrorAction SilentlyContinue # Export and unpack Export-SolutionAndUnpack "$($PatchSolution.uniquename)" -IsPatch } $iterator += 1 } } # Else (patches have static versions) else { foreach ($PatchSolution in $PatchQuery.CrmRecords) { $patchSolutionNames += $PatchSolution.uniquename Export-SolutionAndUnpack "$($PatchSolution.uniquename)" -IsPatch } } # Delete old patch files $exportedPatchSolutionNames = Get-ChildItem -Path $patchFilesFolderPath -Directory | Select-Object -ExpandProperty Name $filteredPatchSolutionNames = $exportedPatchSolutionNames | Where-Object { $patchSolutionNames -notcontains $_ } foreach ($patchName in $filteredPatchSolutionNames) { Write-Host "Deleting patch: $patchName" # Remove the folder and its contents Remove-Item -Path (Join-Path $patchFilesFolderPath $patchName) -Recurse -Force -ErrorAction SilentlyContinue # Remove the managed and unmanaged zip files Remove-Item -Path (Join-Path $deployFilesFolderPath "$patchName.zip") -Force -ErrorAction SilentlyContinue Remove-Item -Path (Join-Path $deployFilesFolderPath "$($patchName)_managed.zip") -Force -ErrorAction SilentlyContinue Write-Host "Deleted patch: $patchName" } } Get-FlowsToBeDeployed "$StartPath" $patchSolutionNames Get-ExportDataValid } catch { Write-Host $_ pause } } function Export-SolutionAndUnpack { Param( [string] [Parameter(Mandatory = $true)] $ExportSolutionName, [switch] $IsPatch ) try { $pacExePath = "$env:APPDATA\Capgemini.PowerPlatform.DevOps\PACTools\tools\pac.exe" $deployFilesFolderPath = (Join-Path $StartPath "Deploy\") # Define the full path for the exported ZIP file $unmanagedExportedZipFilePath = Join-Path $deployFilesFolderPath "$ExportSolutionName.zip" Write-Host "Unmanaged solution file name: $unmanagedExportedZipFilePath" if (!(Test-Path -Path $unmanagedExportedZipFilePath)) { # Export the unmanaged solution to a ZIP file Write-Host "Exporting Unmanaged Solution" & $env:APPDATA\Capgemini.PowerPlatform.DevOps\PACTools\tools\pac.exe solution export -n $ExportSolutionName -p $deployFilesFolderPath --managed false --async --max-async-wait-time 120 # Export the managed solution to a ZIP file Write-Host "Exporting Managed Solution" & $env:APPDATA\Capgemini.PowerPlatform.DevOps\PACTools\tools\pac.exe solution export -n $ExportSolutionName -p $deployFilesFolderPath --managed true --async --max-async-wait-time 120 # Check if the export was successful if (Test-Path -Path $unmanagedExportedZipFilePath) { # If this is a patch, unpack to Patches folder. Otherwise unpack to src folder if ($IsPatch) { Write-Host "Patch solution $ExportSolutionName exported" $destinationFolderPath = (Join-Path $StartPath "Patches\$ExportSolutionName\") } else { Write-Host "Solution exported" Remove-Item (Join-Path $StartPath "src\.") -Force -Recurse -ErrorAction Ignore $destinationFolderPath = (Join-Path $StartPath "src\") } # Unpack the solution (extract the content) Write-Host "Unpacking to destination folder path - " $destinationFolderPath & $env:APPDATA\Capgemini.PowerPlatform.DevOps\PACTools\tools\pac.exe solution unpack --zipfile $unmanagedExportedZipFilePath --folder $destinationFolderPath --packagetype Both --processCanvasApps true } else { Write-PPDOMessage -Message "Solution export of $ExportSolutionName failed - unable to find output file." -Type 'error' -LogError $true } } } catch { Write-Host $_ pause } } function Get-FlowsToBeDeployed { Param( [string] [Parameter(Mandatory = $true)] $StartPath, [array] [Parameter(Mandatory = $false)] $patchSolutionNames ) try { Write-Host "Generating Flows_Default.json for activating post-deploy" $FlowLocations = @(Join-Path $StartPath "src\Workflows") $FlowJSON = @() $AddedFlows = @() # If there are patches if ($patchSolutionNames.Count -gt 0) { foreach ($PatchName in $patchSolutionNames) { $FlowLocations += (Join-Path $StartPath "Patches\$PatchName\Workflows") } } foreach ($FlowLocation in $FlowLocations) { $Workflows = Get-ChildItem -Path $FlowLocation -Filter *.json -ErrorAction SilentlyContinue if ($Workflows) { $Workflows | ForEach-Object { $FlowName = $_.BaseName.SubString(0, $_.BaseName.Length - 36) $FlowID = $_.BaseName.Replace($FlowName, '') if ($AddedFlows -notcontains $FlowID) { $FlowJSON += @([ordered]@{FlowID = $FlowID; FlowName = $FlowName; ActivateAsUser = ""; }) $AddedFlows += $FlowID } } } } if ($FlowJSON.Count -gt 0) { ConvertTo-Json -Depth 3 $FlowJSON | Format-Json | Out-FileUtf8NoBom $StartPath\Flows_Default.json } } catch { Write-Host $_ pause } } |