- Install Ansible on Windows - Thu, Jul 20 2023
- Use Azure Bastion as a jump host for RDP and SSH - Tue, Apr 18 2023
- Azure Virtual Desktop: Getting started - Fri, Apr 14 2023
Let me cut to the chase: although neither Azure PowerShell nor the Azure CLI provides 100 percent coverage of all Azure services, they are reasonably in parity with Azure and with each other. So your decision to prefer one interface over the other largely boils down to:
- Does the Azure service have a preference for PowerShell or the CLI?
- What is my team's scripting language standard?
- Which language is more comfortable for me personally?
I'm going to walk you through some major comparison points between Azure PowerShell and the Azure CLI so you can develop a more informed opinion going forward. Let's begin.
Both are free, open source, and cross-platform
Historically, only the Azure CLI was cross-platform, giving those on the macOS and Linux platforms a command-line interface into Azure. By contrast, Windows PowerShell is bound to .NET Framework and, hence, the Windows operating system.
Nowadays, that isn't the case at all. You can contribute to the PowerShell, Azure PowerShell, and Azure CLI projects over at GitHub:
The fact that Azure PowerShell and the Azure CLI are free and open source means anybody can inspect the code down to its original source. This reduces the vulnerability surface of those CLIs and makes bug fixing much faster.
In terms of architecture, Azure PowerShell is a large collection of modules normally divided by Azure service. When you install Azure PowerShell on your system by downloading from the PowerShell Gallery, you're actually running a bootstrapper module that orchestrates the installation of the rest.
Install-Module -Name Az -Scope CurrentUser -Verbose
NOTE: Microsoft recommends that Windows users install the Azure PowerShell modules into the Current User scope to make sure you don't conflict with modules installed under Windows PowerShell 5.1.
Both are extensible
You extend the functionality of PowerShell's native functionality by creating custom modules. Custom modules allow you to add new cmdlets to Azure PowerShell that can be used to manage specific resources or perform specific tasks.
Extending Azure PowerShell
Here are the two steps required to create a custom module for Azure PowerShell:
Develop the module: Write the code for the new cmdlet or function in PowerShell. The module should follow best practices and use the recommended patterns and practices for PowerShell module development to ensure compatibility and a consistent user experience.
Publish the module: Once you finish developing and testing the module, publish it to a central repository, such as the PowerShell Gallery or a private repository, to make it available to others. You can also distribute it locally, for example, by installing it on a file share or including it in a script library.
We extend the functionality of Azure PowerShell by creating custom extensions. Custom extensions allow you to add new commands to Azure PowerShell that can be used to manage specific resources or perform specific tasks.
Extending Azure CLI
The following are the two main steps required for creating a custom extension for the Azure CLI (spoiler alert: you'll find these steps directly analogous to those for PowerShell custom module development):
Develop the extension: To create a custom extension, you need to write the code for the new commands in either Python or TypeScript. The extension should follow the Azure CLI extension guidelines and use the Azure CLI extension framework to ensure compatibility and a consistent user experience.
Publish the extension: Once the extension is developed, you can publish it to the Azure CLI extension repository, either publicly or privately. This makes the extension available to all users of Azure CLI and makes it easier to distribute and manage.
To install a custom extension, users simply need to use the Azure CLI command az extension add and specify the name of the extension. For example, here's the code to add the Azure DevOps extension to your Azure CLI installation:
az extension add –name azure-devops
The Azure CLI interactive environment shown in the following screenshot is invoked via an extension as well.
Syntax differences
PowerShell has been around for a long time, so I trust you're already familiar with its consistent, verb-noun command syntax.
The Azure CLI, by contrast, offers a consistent but less intuitive syntax (at least to me; your mileage may vary). It's pretty clear to me that the Azure CLI software engineers had Linux users in mind when they created the language.
It's also important to note that PowerShell is an actual shell environment, while the Azure CLI is a command-line interface that resides within a separate shell environment such as Bash or even PowerShell.
Azure PowerShell was written in C#; the Azure CLI is a Python application.
Now let's get to some code samples:
Here's how we can deploy a Bicep template to the Azure resource group scope by using Azure PowerShell:
New-AzResourceGroupDeployment -Name 'storage-acct-deploy' -ResourceGroupName '4sysops-rg' -TemplateFile './stgacct.bicep'
Here, we deploy a Bicep template to the Azure resource group scope by using the Azure CLI:
az deployment group create –name 'storage-acct-deploy' -resource-group '4sysops-rg' –template-file './stgacct.bicep'
Pretty similar? However, the Azure CLI really begins to show its Linux syntax foundations when you create more complex logic, particularly using JMESPath filters. For instance, this command searches for all Azure storage accounts that have their default access tier set to Hot:
az storage account list -g '4sysops-rg' --query "[?accessTier == 'Hot' && sku.tier == 'Standard]{myId:id,name:name,sku:sku.name}" -otable
Azure service coverage differences
Internally at Microsoft, Azure product groups are supposed to offer customers equal access to their data plane APIs with both Azure PowerShell and the Azure CLI. However, in practice, this isn't the case for various reasons.
You'll find that some Azure services have much better support for the Azure CLI (the Azure container services, for instance). Other services are weighted toward PowerShell (Azure Automation, for example).
The Microsoft Learn docs say it directly:
Feature parity for Azure services doesn't always exist between Azure CLI and Azure PowerShell.
What does this mean? You need to read the docs in depth for each Azure service your team's considering, and check out the degree of Azure PowerShell support vs. the Azure CLI.
Programmability differences
The Azure CLI outputs JSON strings, while Azure PowerShell outputs .NET objects. If you're accustomed to Bash shell scripting, you're comfortable with managing text output and working within its constraints.
By contrast, PowerShell offers administrators a much more robust object-oriented programming (OOP) environment. You can define classes and advanced functions using a familiar syntax and leverage the events, methods, and properties that have always been fundamental to .NET.
Wrap-up
So how are you feeling about Azure PowerShell vs. the Azure CLI? I'd like to stress that the choice can just as well be "both/and" rather than "either/or." For instance, you might lean toward the Azure CLI if:
- The Azure services you use support it well
- You are more accustomed to Bash shell scripting
- You need to "get in and get out" running Azure management commands quickly
On the other hand, you might prefer Azure PowerShell if:
Subscribe to 4sysops newsletter!
- The Azure services you use support it well
- You have more complex automation scripts that require OOP logic
- You already use PowerShell in other contexts
Please leave your feedback in the comments.
Good article, nicely written. Another similarity is that from azure portal, one can launch a cloud shell in either of these two environments.
I think it’s great that both are available. For someone coming from a Linux background, the AZ CLI is really familiar and consistent with what they’re used to. For me, who has a lot of PowerShell experience, I’m much happier with AZ PowerShell. I’m so used to having my outputs be objects, it’s always a frustration to get the output from AZ CLI.
At least I found “-o table” for AZ CLI, which helps a lot. But filtering properties, I have to look up the reference on how to do it every time.
100 percent on the difficulty in filtering properties. Honestly, that makes CLI a dealbreaker for me in many contexts. Thanks for reading! -Tim