Using PowerShell Files in Azure DevOps Pipelines
My Learning Experience
Navigating environment variables, outputs, parameters, and other variables in pipelines can be a daunting task within Azure DevOps. With various methods for accessing variables, inconsistencies in casing, and numerous other challenges, the process can be far from straightforward.
My advice, learned through rigorous trial and error, is to steer clear of these complexities whenever possible or, at the very least, to encapsulate any code snippets exceeding two lines within PowerShell scripts.
By adopting this approach, not only can you streamline your pipeline processes, but you also gain the flexibility to test individual components separately.
A Practical Example
Executing a Bicep file within pipelines is a common requirement, yet passing parameters to Bicep can often be time-consuming and convoluted. To mitigate these challenges, I strongly recommend crafting a helper script. Such a script can be developed locally and seamlessly integrated into the pipeline once finalized.
param (
[Parameter(Mandatory=$true)]
[string]$templateFile1,
[Parameter(Mandatory=$true)]
[string]$resourceGroup,
[Parameter(Mandatory=$true)]
[string]$projectname,
[Parameter(Mandatory=$true)]
[string]$location,
[Parameter(Mandatory=$true)]
[string]$environment,
[Parameter(Mandatory=$true)]
[string]$iotHubName
)
$deploymentName = "deploy-part-1-$projectname-$environment"
Write-Host "Deploy Infrastructure with Bicep"
Write-Host "- deploymentName : $deploymentName"
Write-Host "- bicepScriptPath: $templateFile1"
Write-Host "- location : $location"
Write-Host "- projectname : $projectname"
Write-Host "- resourceGroup : $resourceGroup"
Write-Host "- env : $environment"
Write-Host "- iotHubName : $iotHubName"
$deploymentResult = az deployment group create `
--resource-group $resourceGroup `
--template-file $templateFile1 `
--name $deploymentName `
--parameters `
name=$projectname `
location=$location `
env=$environment `
iothubName=$iotHubName
| ConvertFrom-Json
$outputs = $deploymentResult.properties.outputs
$powerbiFunctionAppName = $outputs.powerbiFunctionAppName.value
$settingsFunctionAppName = $outputs.settingsFunctionAppName.value
$storageAccountName = $outputs.storageAccountName.value
# Some outputs for the pipeline later
Write-Host "##vso[task.setvariable variable=POWERBI_FUNCTION_APP_NAME;isOutput=true;]$powerbiFunctionAppName"
Write-Host "##vso[task.setvariable variable=SETTINGS_FUNCTION_APP_NAME;isOutput=true;]$settingsFunctionAppName"
Write-Host "##vso[task.setvariable variable=STORAGE_ACCOUNT_NAME;isOutput=true;]$storageAccountName"
Write-Host "- Power Bi Function App Name : $powerbiFunctionAppName"
Write-Host "- Settings Function App Name : $settingsFunctionAppName"
Write-Host "- Storage Account Name : $storageAccountName"
# Some outputs for local usage
$env:SETTINGS_FUNCTION_APP_NAME = $settingsFunctionAppName
$env:POWERBI_FUNCTION_APP_NAME = $powerbiFunctionAppName
$env:STORAGE_ACCOUNT_NAME = $storageAccountName
if ($null -eq $powerbiFunctionAppName) {
Write-Error "- Powerbi Function App Name is null"
Exit 1
return
}
if ($null -eq $settingsFunctionAppName) {
Write-Error "- Settings Function App Name is null"
Exit 1
return
}
if ($null -eq $storageAccountName) {
Write-Error "- Storage Account Name is null"
Exit 1
return
}
$waitSeconds = 30
write-Host "- Wait $waitSeconds seconds for the function app to be ready"
Start-Sleep -Seconds $waitSeconds
Conclusion
By segregating scripts for local testing and subsequent integration within pipelines, you can enhance both the efficiency and reliability of your deployment processes.
About the Author / Oliver Scheer
Meet Oliver, a Principal Software Engineer at Medialesson, boasting over 25 years of software development expertise across real and challenging customer projects. With 17 years of experience at Microsoft as both an Evangelist and Software Engineer, Oliver's focus lies in .NET, DevOps, Developer Experiences, and Cloud technologies. For more about Oliver, visit his website or LinkedIn profile.