Microsoft.PowerPlatform.DevOps.psm1
Write-Verbose "Importing Functions" # Import everything in these folders foreach ($folder in @('private', 'public', 'classes')) { $root = Join-Path -Path $PSScriptRoot -ChildPath $folder if (Test-Path -Path $root) { Write-Verbose "processing folder $root" $files = Get-ChildItem -Path $root -Filter *.ps1 # dot source each file $files | where-Object { $_.name -NotLike '*.Tests.ps1' } | ForEach-Object { Write-Verbose $_.name; . $_.FullName } } } if (!(Test-Path "$env:APPDATA\Microsoft.PowerPlatform.DevOps")) { New-Item -Path "$env:APPDATA\Microsoft.PowerPlatform.Devops" -ItemType Directory } if (!(Test-Path "$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json")) { Copy-Item (Join-Path $PSScriptRoot "\devopsConfig.json") -Destination "$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json" } $global:configFile = Get-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json") | ConvertFrom-Json $global:version = Get-ManifestValue (Join-Path $PSScriptRoot "\Microsoft.PowerPlatform.DevOps.psd1") -PropertyName 'ModuleVersion' -Passthru $global:projectFile = "False" $global:gitRepo = "" if ($global:projectFile -eq "False") { $global:projectTitle = "(No Project Selected)" } else { $global:projectTitle = $global:projectFile.gitRepo } $global:logo = @" ____ ____ _ _ __ ____ ___ | _ \ _____ _____ _ __ | _ \| | __ _| |_ / _| ___ _ __ _ __ ___ | _ \ _____ __/ _ \ _ __ ___ | |_) / _ \ \ /\ / / _ \ '__| | |_) | |/ _` | __| |_ / _ \| '__| '_ ` _ \ | | | |/ _ \ \ / / | | | '_ \/ __| | __/ (_) \ V V / __/ | | __/| | (_| | |_| _| (_) | | | | | | | | | |_| | __/\ V /| |_| | |_) \__ \ |_| \___/ \_/\_/ \___|_| |_| |_|\__,_|\__|_| \___/|_| |_| |_| |_| |____/ \___| \_/ \___/| .__/|___/ |_| "@ $global:message = @" Welcome to the Power Platform DevOps configuration script. ver: $global:version project: $global:projectTitle "@ function Install-PreReqs { $message = "Checking Pre-requisites" Write-Host $message try { Invoke-InstallPreRequisites $global:configfile.PreReqsComplete = "True" } catch { $global:configfile.PreReqsComplete = "Error" pause } $global:configfile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json") } function Connect-AzureDevOps { $message = "Configuring Azure DevOps" Write-Host $message try { Invoke-AzureDevOps $global:projectFile.ADOConfigured = "True" } catch { $global:projectFile.ADOConfigured = "Error" pause } $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json") } function Add-Solution { $message = "Adding D365 / CDS Solution" Write-Host $message try { Invoke-AddSolution $global:projectFile.SolutionAdded = "True" } catch { $global:projectFile.SolutionAdded = "Error" pause } $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json") } function Add-CICDEnvironment { $message = "Configuring CI/CD Environment" Write-Host $message try { Invoke-ConfigureCICD } catch { $global:projectFile.CICDEnvironmentName = "Error" pause } $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json") } function Add-Project { $message = "Adding PowerPlatform DevOps Project" Write-Host $message if ($global:configfile.Projects.Count -gt 1 -or $global:configfile.Projects[0].ID -ne "placeholder") { do { $createOrSelect = Read-Host "Do you want to [S]elect and Existing Project or [C]reate a new one? ([Q]uit)" switch ($createOrSelect) { 'C' { Add-GitRepo } 'S' { Select-GitRepo } } } until (($createOrSelect -eq 'q') -or ($createOrSelect -eq 'c') -or ($createOrSelect -eq 's')) } else { Add-GitRepo } try { } catch { $global:projectFile.SolutionAdded = "Error" pause } #$global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json") $global:configfile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json") } function Export-Solution { if ($global:projectFile.CDSSolutions.Count -gt 0) { $options = $global:projectFile.CDSSolutions | ForEach-Object { $_.SolutionName } do { $sel = Invoke-Menu -MenuTitle "---- Please Select the Solution to Export and Unpack ------" -MenuOptions $options $selectedSolution = $global:projectFile.CDSSolutions[$sel].SolutionName } until ($selectedSolution -ne "") Write-Host $selectedSolution Write-Host $global:projectFile.ProjectLocation Set-Location -Path "$($global:projectFile.ProjectLocation)\$selectedSolution\Scripts" if ($global:projectFile.ADOConfigured -eq "True") { try { git pull origin } catch { pause } } & .\SolutionExport.ps1 Set-Location -Path $global:projectFile.ProjectLocation } } function Sync-Solution{ $commitMessage = Read-Host "Enter a description for your Commit" git add -A git commit -m $commitMessage if ($global:projectFile.ADOConfigured -eq "True") { git push origin } pause } function Show-SolutionChanges{ git status pause } function Enable-AzureDeploy{ if ($global:projectFile.ARMAdded -ne "True") { Copy-Item -Path (Join-Path $PSScriptRoot Snippets\AzureResources\.) -Destination $global:projectFile.ProjectLocation -Recurse -Force $buildYAML = Get-Content -Path "$($global:projectFile.ProjectLocation)\Build.yaml" $azureYAML = Get-Content -Path (Join-Path $PSScriptRoot Snippets\AzureDeploy.yaml) $azureYAML = $azureYAML.Replace('replaceRepo', $global:projectFile.gitRepo) $buildYAML + $azureYAML | Set-Content -Path "$($global:projectFile.ProjectLocation)\Build.yaml" $azureParams = Get-Content -Path "$($global:projectFile.ProjectLocation)\AzureResources\azuredeploy.parameters.json" $azureParams = $azureParams.Replace('AddName', $global:projectFile.gitRepo) $azureParams | Set-Content -Path "$($global:projectFile.ProjectLocation)\AzureResources\azuredeploy.parameters.json" $adoOrg = $global:projectFile.ADOOrgName $adoProject = $global:projectFile.ADOProject $adoRepo = $global:projectFile.gitRepo.ToLower() $varGroupAzure = az pipelines variable-group create --organization https://dev.azure.com/$adoOrg --project $adoProject --name "$($global:projectFile.gitRepo).AzureEnvironment" --variables AzureResourceGroup="" --authorize $true | ConvertFrom-Json az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name AzureAppInsightsName --value "$adoRepo-staging-ai" --group-id $varGroupAzure.id az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name AzureLocation --value "australiaeast" --group-id $varGroupAzure.id az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name AzureStorageAccountName --value "$adoRepo-staging" --group-id $varGroupAzure.id az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name AzureFunctionAppName --value "$adoRepo-staging-fna" --group-id $varGroupAzure.id az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name AzureWebAppName --value "$adoRepo-staging-wba" --group-id $varGroupAzure.id az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name WorkspaceName --value "$adoRepo-staging-log" --group-id $varGroupAzure.id az pipelines variable-group variable create --organization https://dev.azure.com/$adoOrg --project $adoProject --name AzureKeyVaultName --value "$adoRepo-staging-kv" --group-id $varGroupAzure.id $global:projectFile.ARMAdded = "True" $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json") Write-Host "Please make sure you follow the instructions for configuring a Service Connection in Azure DevOps, as detailed in $($global:projectFile.ProjectLocation)\AzureResources\Instructions.md" -ForegroundColor Yellow pause } else { Write-Host "Azure Deployment Already Enabled for this Project" pause } } function Enable-FunctionApp{ if ($global:projectFile.FunctionAppAdded -ne "True") { Copy-Item -Path (Join-Path $PSScriptRoot Snippets\FunctionApp\.) -Destination $global:projectFile.ProjectLocation -Recurse -Force dotnet sln $global:gitRepon.sln add FunctionApp\FunctionApp.csproj $global:projectFile.FunctionAppAdded = "True" $global:projectFile | ConvertTo-Json | Set-Content ("$env:APPDATA\Microsoft.PowerPlatform.Devops\$global:gitRepo\$global:gitRepo.json") pause } else { Write-Host "Function App Already Enabled for this Project" pause } } function Show-Menu { param ( [string]$Title = 'Power Platform DevOps' ) $devopsConfigMessage = "(ADO Org : $($global:projectFile.ADOOrgName) | ADO Project : $($global:projectFile.ADOProject) | git Repo : $($global:projectFile.gitRepo))" $CICDConfigMessage = "(CI/CD Environment : $($global:projectFile.CICDEnvironmentName) | CI/CD URL : $($global:projectFile.CICDEnvironmentURL))" if ($global:projectFile -eq "False") { $Title = "Power Platform DevOps (No Project Selected)" } else { $Title = "Power Platform DevOps ($($global:projectFile.gitRepo))" $global:projectTitle = $global:projectFile.gitRepo Set-Location $global:projectFile.ProjectLocation } [console]::ForegroundColor = "White" Clear-Host Write-Host $global:logo -ForegroundColor Magenta Write-Host $global:message -ForegroundColor White $Repeater = "=" * $Title.Length Write-Host "================ $Title ================" -ForegroundColor White Write-Host "1: Run Pre-requisite checks (Install / Update)." -ForegroundColor (Set-Colour $global:configfile.PreReqsComplete) if (($global:configfile.PreReqsComplete -eq "True")) { Write-Host "2: Create a New Project or Select and Existing One" -ForegroundColor (Set-Colour $global:projectFile) } if (!($global:projectFile -eq "False") -and ($global:configfile.PreReqsComplete -eq "True")) { Write-Host "3: Configure Azure DevOps" $devopsConfigMessage -ForegroundColor (Set-Colour $global:projectFile.ADOConfigured) Write-Host "4: Add New D365 / CDS Solution." -ForegroundColor (Set-Colour $global:projectFile.SolutionAdded) if ($global:projectFile.ADOConfigured -eq "True" -and $global:projectFile.SolutionAdded -eq "True") { Write-Host "5: Configure Continuous Deployment" $CICDConfigMessage -ForegroundColor (Set-Colour $global:projectFile.CICDEnvironmentName) } Write-Host "A: Enable [A]zure Resource Management Deployment." -ForegroundColor (Set-Colour $global:projectFile.ARMAdded) Write-Host "F: Add Azure [F]unction App Project." -ForegroundColor (Set-Colour $global:projectFile.FunctionAppAdded) if ($global:projectFile.SolutionAdded -eq "True") { Write-Host "D: Add Additional [D]365 / CDS Solutions" -ForegroundColor Cyan Write-Host "E: [E]xport & Unpack Solution to Source Control" -ForegroundColor Cyan Write-Host "S: Commit and [S]ync changes to Source Control" -ForegroundColor Cyan Write-Host "V: [V]iew current change log for Source Control" -ForegroundColor Cyan } if ($global:projectFile.CICDEnvironmentName -ne "False") { Write-Host "T: Add Additional Deployment Environment [T]arget" -ForegroundColor Cyan } } Write-Host "Q: Press 'Q' to quit." -ForegroundColor White Write-Host "=================$Repeater=================" -ForegroundColor White Write-Host "" Write-Host "* (White items still need to be completed)" -ForegroundColor White Write-Host "* (Green items are successful)" -ForegroundColor Green Write-Host "* (Red items have Errors)" -ForegroundColor Red Write-Host "* (Purple items are optional)" -ForegroundColor Magenta Write-Host "* (Blue Items are used for Day-to-Day ALM)" -ForegroundColor Cyan Write-Host "" } function Invoke-PowerPlatformDevOps { Write-Host "" [console]::ForegroundColor = "White" do { $global:configFile = Get-Content ("$env:APPDATA\Microsoft.PowerPlatform.DevOps\devopsConfig.json") | ConvertFrom-Json if ($global:projectFile -ne "False") { $global:gitRepo = $($global:projectFile.gitRepo) Set-Location $global:projectFile.ProjectLocation } Show-Menu $selection = Read-Host "Please make a selection" switch ($selection) { '1' { Install-PreReqs } '2' { Add-Project } '3' { Connect-AzureDevOps } '4' { Add-Solution } '5' { Add-CICDEnvironment } 'D' { Add-Solution } 'E' { Export-Solution } 'S' { Sync-Solution } 'V' { Show-SolutionChanges } 'T' { Add-TargetEnvironment } 'A' { Enable-AzureDeploy } 'F' { Enable-FunctionApp } } Write-Host "" } until ($selection -eq 'q') } Export-ModuleMember -Function 'Invoke-PowerPlatformDevOps' #, 'Add-CICDEnvironment', 'Add-Solution', 'Connect-AzureDevOps', 'Install-PreReqs' |