Azure CLI 2.89: A Python-based command surface for Azure, with scripting quirks you should know
Azure Command-Line Interface. | Common scenarios and use Azure CLI effectively Please check Tips for using Azure CLI effectively.
At a glance
- What is it?
- Microsoft's Azure CLI is a multi-platform Python tool for managing Azure resources. This review covers its command structure, output formats, exit codes, telemetry defaults, and where it fits compared to PowerShell or REST-based tooling.
- Who is it for?
- Adopt Azure CLI if your team works across Linux, macOS, and Windows and wants a single Python-based tool with consistent command groups and JMESPath querying. Do not adopt it if you need deep PowerShell integration, if you cannot tolerate a default-on telemetry that requires an explicit opt-out, or if you prefer a thin REST client over a large command surface.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What Azure CLI actually is and who should care
The core value is that you can script resource lifecycle operations without writing bespoke REST calls. The CLI handles authentication, request signing, and response parsing for you. That saves time, but it also means you depend on Microsoft's command implementations. If a command does not exist for a new service, you wait for a release. The README does not promise coverage of every Azure API, and the repository layout suggests a large, evolving codebase. For a team that needs to automate Azure today, the CLI is a reasonable default, but you should verify that the specific services you use are represented.
Command structure and the help system
The usage pattern is `az [ group ] [ subgroup ] [ command ] {parameters}`. Groups map to Azure services, like `az storage` or `az vm`. The README shows `az storage -h` and `az vm create -h` as ways to get help. Help is per command, not global, which is a small friction point. You must know the group and subgroup before you can ask for help. Tab completion helps: the README demonstrates completing resource group names and VM names after `-g` and `-n`. That completion works for groups, commands, and some parameters, according to the README. It is not guaranteed for every argument, so scripts that rely on completion are fragile. The help output is standard for a CLI, but the real power is in the output formatting and query language, which are covered in the next sections.
Output formats: table, JSON, and the JMESPath query
The CLI supports multiple output formats. The README highlights `--output table` for human-readable results and `az configure` to change the default. The table format is useful for interactive work, but for scripts you will want JSON or TSV. The `--query` parameter accepts JMESPath, a JSON query language. The README gives an example: `az vm list --query "[?provisioningState=='Succeeded'].{ name: name, os: storageProfile.osDisk.osType }"` which filters VMs by provisioning state and projects selected fields. That is a concrete mechanism for shaping output without piping to `jq`. The combination of `--query` and `--output table` means you can get a clean table from a filtered query, as the README shows. For automation, you can use `--output tsv` to get tab-separated values, though the README does not show an example. The flexibility is real, but it comes with a learning curve: JMESPath is a separate syntax you must learn. If your team already knows `jq`, the CLI's query language is an additional tool, not a replacement.
Exit codes: a scripting contract with a trap
The README documents four exit codes. 0 means success. 1 is a generic error, such as a bad status from the server or a CLI validation failure. 2 is a parser error, meaning your command line was malformed. 3 is specific: a missing ARM resource, used for existence checks from `show` commands. This is a useful contract for scripts, because you can distinguish a missing resource from a generic failure. However, the trap is that not all commands return 3. The README says it is used for `show` commands, not for `list` or `delete`. If you script a `delete` on a nonexistent resource, you will get a 1, not a 3. You must test each command's exit behavior. Also, exit code 2 for parser errors means that a typo in a parameter name is distinguishable from a server error, which is good for debugging, but it also means your script must handle three failure modes, not one.
Installation paths: Docker, edge builds, and the official guide
Installation is not a single command. The README points to a detailed install guide at learn.microsoft.com, and lists common issues in a troubleshooting doc. For developers, there are three paths. Docker: `docker run -u $(id -u):$(id -g) -v ${HOME}:/home/az -e HOME=/home/az --rm -it mcr.microsoft.com/azure-cli:<version>`. That command runs the CLI as your user ID and mounts your home directory, which avoids permission problems with cached credentials. Edge builds are available as MSI for Windows, Homebrew for macOS, and Ubuntu binaries, linked from aka.ms URLs. These are builds from the `dev` branch, so they are not stable releases. The README does not mention pip installation, but the package is on PyPI, as the badge suggests. For a production environment, you should use a tagged release like 2.89.1, not an edge build. The Docker image is a good choice for CI, because you can pin a version tag and avoid host dependencies.
Telemetry is on by default: a real governance issue
The README states plainly: "Telemetry collection is on by default." To opt out, you run `az config set core.collect_telemetry=no`. This is a config key, not a command-line flag. The data collection section says Microsoft may collect information about your use and send it to Microsoft, and that your use operates as consent. For an organization with strict data policies, this is a significant consideration. The opt-out is simple, but it must be applied to every machine and every CI agent. The README does not say whether the setting is per-user or per-system, so you may need to set it in a script that runs before any `az` command. The default-on telemetry is a design choice that favors Microsoft's product improvement over user privacy. If you adopt the CLI, you must decide whether to accept that or enforce the opt-out. The README also mentions that some features may enable you to collect data from your own users, which is a separate compliance burden.
Where it falls short: limitations and the wrong tool cases
The CLI is large, and that size has consequences. The README does not list a command count, but the repository covers many services, which means the tool is not lightweight. On a slow network or a constrained CI container, the initial install and every update can be heavy. The CLI also assumes a live connection to Azure; there is no offline mode for command help beyond what is cached. For scripting, the exit code 3 behavior is limited to `show` commands, as noted, so you cannot rely on it for all existence checks. The CLI is the wrong tool if you need to interact with Azure's REST API directly for a new or undocumented feature. The README mentions `az rest` in the tips document, but the repository material does not detail it. If you need fine-grained control over HTTP requests, a tool like `curl` with a token is more direct. Also, if your team is heavily invested in PowerShell, the Azure PowerShell module may integrate better with your existing scripts, though the README does not compare the two.
Alternatives and the practical difference
The main alternative is Azure PowerShell, which is a separate module set. The difference is the command model: Azure CLI uses a noun-verb pattern with groups like `az vm create`, while PowerShell uses verb-noun cmdlets like `New-AzVM`. That affects how you write scripts and how you pass parameters. PowerShell cmdlets return .NET objects, so you can pipe them to other PowerShell commands without parsing text. The CLI returns JSON strings, which you must parse with `--query` or an external tool. If your automation is entirely in PowerShell, the module is a natural fit. Another alternative is using the Azure REST API directly with a tool like `curl` or a language SDK. That gives you full control over every request, but you must handle authentication and pagination yourself. The CLI abstracts those away, which is its advantage. For a team that values a single tool across platforms, the CLI wins. For a team that lives in PowerShell, the module is less disruptive. The README does not compare these, so this is my assessment based on the documented behavior.
Editorial conclusion
Adopt Azure CLI if your team works across Linux, macOS, and Windows and wants a single Python-based tool with consistent command groups and JMESPath querying. Do not adopt it if you need deep PowerShell integration, if you cannot tolerate a default-on telemetry that requires an explicit opt-out, or if you prefer a thin REST client over a large command surface. Before committing, verify that the command groups you rely on are stable in your release, check how your CI pipeline handles exit code 3 for missing resources, and run `az config set core.collect_telemetry=no` in every environment that must not send usage data. The CLI is a pragmatic choice for automation, but its size and telemetry defaults mean you should pin a version and audit your scripts.
Community notes