PowerShell and Azure CLI
Azure CLI is a good alternative to using Azure PowerShell. It is idempotent, and is a great fit for Continuos Integration scenarios. But in the process of making Azure Cli compatible with bash
pwsh
cmd
etc, az
does not fit PowerShell when automated. Most problems can be solved with some helper functions, and this post is here to show you how.
In this article I will show you my approach to a helper method to ensure and monitor Azure Cli results, in Power Shell.
Skip to the end if you just want some code to copy. 🖨
This article was written with az cli v2.13.0
and PowerShell 5.0+
in mind.
Non-working example
Lets start off with a non-working example to show what is the problem with az
commands in PowerShell
# Configure Error Action Preference Stop to stop on any error
$ErrorActionPreference = 'Stop'
# Create and setup app-service
az webapp create --resource-group $resourceGroup --name $appName
az webapp config set `
--resource-group $resourceGroup `
--name $appName `
--always-on $true `
--ftps-state FtpsOnly
Why does this not work?
If the first az webapp create
fails, execution will continue. The az webapp config
will also fail as a result. But the script will happily continue. If this was on your CI pipeline no error would be reported, and the CI build would be Green.
How can I avoid continuing on errors?
Check $LASTEXITCODE
after every az
command. If az
has an error, it will print the error to console and exit with a non-zero ExitCode.
az webapp create --resource-group $resourceGroup --name $appName
if ($LASTEXITCODE -ne 0) {
Write-Error "az failed with exit code $LASTEXITCODE" -ErrorAction 'Stop'
}
This seems like a lot of code to write on every az
command?
Helper methods to the rescue. We can create a simple “Test” to ensure the exit code is non-zero.
Function Test-LastExitCode {
if($LastExitCode -ne 0 ) {
Write-Error "Operation failed with exit code $LastExitCode" -ErrorAction 'Stop'
}
}
# We now have a single line error handling
az webapp create --resource-group $resourceGroup --name $appName
Test-LastExitCode
Using az
output in PowerShell
az
by default returns a JSON result if the command is successful. This can be converted to PowerShell objects for easy consumption. If it errors, the result is always empty or null.
We pipe the result into ConvertFrom-Json
to parse this into a powershell native format.
$appInfo = az webapp create --resource-group $resourceGroup --name $appName | ConvertFrom-Json
Test-LastExitCode
# Use the returned data as a Powershell Object, nice!
Write-Output $appInfo.defaultHostName
Combining Error Handling and Output
What if we use the powershell pipe to both parse the exit code and the Json result?
The full code of the PowerShell az cli
converter I use is found below. Include this in a module, or at the top of your file for reliable az
scripting. 🚀
Function ConvertFrom-AzureCli {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline)] [string] $line
)
begin {
# Collect all lines in the input
$lines = @()
}
process {
# 'process' is run once for each line in the input pipeline.
$lines += $line
}
end {
# Azure Cli errors and warnings change output colors permanently.
# Reset the shell colors after each operation to keep consistent.
[Console]::ResetColor()
# If the 'az' process exited with a non-zero exit code we have an error.
# The 'az' error message is already printed to console, and is not a part of the input.
if ($LASTEXITCODE) {
Write-Error "az exited with exit code $LASTEXITCODE" -ErrorAction 'Stop'
}
$inputJson = $([string]::Join("`n", $lines));
# We expect a Json result from az cli if we have no error. The json result CAN be $null.
$result = ConvertFrom-Json $inputJson
return $result
}
}
Best-practice usage:
# I recommend using StrictMode to catch issues such as missing fields and unused variables early
Set-StrictMode -Version 'latest'
$ErrorActionPreference = 'Stop'
# Ensure app-service exists
$appInfo = (az webapp create `
--resource-group $resourceGroup `
--name $appName `
| ConvertFrom-AzureCli
)
# Ensure app-service configuration
az webapp config set `
--ids $appInfo.id `
--always-on $true `
--ftps-state FtpsOnly `
| ConvertFrom-AzureCli
Write-Output "Success!"
That’s all! I hope this could help setup a better PowerShell and Azure CLI pipeline.
Code Snippets are licensed under MIT No Attribution