cheat sheet

az

Cross-platform command-line interface for managing Azure resources, running ARM-based and data-plane operations from a terminal or pipeline.

az — Azure CLI

What it is

az is Microsoft's official command-line tool for managing Azure resources. It is a Python application maintained at Azure/azure-cli (current stable: 2.87.0, released June 2026) that wraps the Azure Resource Manager REST API plus a long list of data-plane services (Storage, Key Vault, Container Registry, Batch, etc.). Reach for it when you want a single uniform interface for shell scripts, CI pipelines, and ad-hoc cloud operations — alternatives are Azure PowerShell (Az modules), the Azure Portal, Terraform, and Bicep, but az is the lightest-weight and most universally available.

Install

az ships as native packages on every major OS, as a tarball, and via pip/conda. Microsoft maintains an apt repo for Debian/Ubuntu and a dnf/yum repo for RHEL/Fedora; the official one-line installer is the fastest path on Linux.

bash
# Debian/Ubuntu — official Microsoft repo
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# RHEL / Fedora / Rocky / Alma
sudo dnf install -y azure-cli

# macOS
brew update && brew install azure-cli

# Windows (PowerShell, run as admin)
winget install --exact --id Microsoft.AzureCLI

# Cross-platform via pip (inside a venv)
python3 -m pip install --user azure-cli

# Verify
az version

Output:

json
{
  "azure-cli": "2.87.0",
  "azure-cli-core": "2.87.0",
  "azure-cli-telemetry": "1.1.0",
  "extensions": {}
}

Syntax

Every az invocation follows a verb-noun command group structure. The first positional token after az is a command group (a service like vm, storage, network), followed by a sub-group or action, then flags.

bash
az <command-group> [<sub-group>] <action> [--global-flags] [--command-flags]

Output: (none — exits 0 on success)

A few concrete shapes:

bash
az login
az account show
az group create --name MyResourceGroup --location westus2
az vm list --resource-group MyResourceGroup --output table
az storage blob upload --account-name alicedev01 --container-name data --name report.csv --file ./report.csv

Output: (none — see per-command sections below)

Essential options

OptionMeaning
--help / -hPrint help for the current command group or command. az vm --help lists every sub-command.
--output / -oOutput format: json (default), jsonc, yaml, yamlc, table, tsv, none.
--queryJMESPath expression filtering the response — runs locally after the API call.
--subscriptionOverride the active subscription for one command. Takes a name or GUID.
--resource-group / -gTarget resource group. With defaults.group set, you can omit it.
--location / -lAzure region (e.g. westus2, eastus, northeurope).
--verboseINFO-level logging to stderr.
--debugDEBUG-level logging including HTTP request/response (useful for failures).
--only-show-errorsSuppress warnings (preview/deprecation banners). Good for CI.
--no-waitReturn immediately for long-running operations rather than polling.
--yes / -ySkip confirmation prompts.

Configuration

az reads settings from three layers — command-line flags, environment variables, and an INI config file — in that precedence order. The config file path is $AZURE_CONFIG_DIR/config (defaults to ~/.azure/config on Linux/macOS and %USERPROFILE%\.azure\config on Windows). Reach for the file (or az config set) when you want a setting to persist across shells; reach for environment variables when scripting CI; reach for flags for one-off overrides.

File locations

OSPathNotes
Linux$AZURE_CONFIG_DIR/config (defaults to ~/.azure/config)Per-user only; system-wide configs are not supported. Tokens and contexts live alongside in the same directory.
macOS~/.azure/config (same default — not the App Support directory)Identical to Linux.
Windows%USERPROFILE%\.azure\config (e.g. C:\Users\Alice Dev\.azure\config)Roaming-profile path. Same INI format as Linux/macOS.

Loading precedence (highest to lowest):

  1. Command-line parameters (--output table, --subscription …)
  2. Environment variables (AZURE_CORE_OUTPUT=table, AZURE_DEFAULTS_GROUP=…)
  3. Values written to $AZURE_CONFIG_DIR/config by az config set or az init
  4. Built-in defaults

Options reference — every option is exposed both in the INI file ([section]key) and as an environment variable named AZURE_{SECTION}_{KEY} (all uppercase). For example, [core] output = table is equivalent to AZURE_CORE_OUTPUT=table.

Core

OptionTypeDefaultPossible valuesDescription
core.outputenumjsonjson | jsonc | yaml | yamlc | table | tsv | noneDefault output format when --output is not passed.
core.disable_confirm_promptboolfalsetrue | falseSkip all confirmation prompts (Are you sure?).
core.collect_telemetrybooltruetrue | falseSend anonymous usage telemetry to Microsoft.
core.only_show_errorsboolfalsetrue | falseSuppress preview/deprecation warnings on stderr.
core.no_colorboolfalsetrue | falseDisable ANSI color in stdout/stderr.
core.enable_broker_on_windowsbooltruetrue | falseUse Web Account Manager (WAM) for az login on Windows.
core.login_experience_v2booltruetrue | falseShow the multi-subscription picker after az login.
core.display_region_identifiedbooltruetrue | falseShow region-recommendation message when CLI detects a closer region.
core.survey_messageenumyesyes | noShow the periodic CLI satisfaction survey banner.

Logging

OptionTypeDefaultPossible valuesDescription
logging.enable_log_fileboolfalsetrue | falseWrite a rolling log file in addition to stderr.
logging.log_dirstring${AZURE_CONFIG_DIR}/logsany writable directoryDirectory for log files when enable_log_file=true.

Defaults (implicit arguments)

OptionTypeDefaultPossible valuesDescription
defaults.groupstring""any RG nameResource group used when -g is omitted.
defaults.locationstring""any Azure regionLocation used when -l is omitted (e.g. westus2).
defaults.webstring""any web app nameDefault app for az webapp commands.
defaults.vmstring""any VM nameDefault VM for az vm commands.
defaults.vmssstring""any VMSS nameDefault scale set for az vmss commands.
defaults.acrstring""any registry nameDefault container registry for az acr commands.

Storage data-plane

OptionTypeDefaultPossible valuesDescription
storage.accountstring""storage account nameDefault account for az storage data-plane commands.
storage.keystring""account keyDefault access key (avoid — prefer RBAC).
storage.sas_tokenstring""SAS tokenDefault SAS token for data-plane calls.
storage.connection_stringstring""connection stringDefault connection string used in place of account+key.

Cloud

OptionTypeDefaultPossible valuesDescription
cloud.nameenumAzureCloudAzureCloud | AzureChinaCloud | AzureUSGovernmentActive sovereign cloud. Switch with az cloud set --name.

Batch

OptionTypeDefaultPossible valuesDescription
batch.accountstring""account nameDefault Batch account.
batch.access_keystring""shared keyDefault access key (used with auth_mode=shared_key).
batch.endpointstring""URLDefault Batch endpoint.
batch.auth_modeenumshared_keyshared_key | aadAuthentication mode for az batch commands.

Extension

OptionTypeDefaultPossible valuesDescription
extension.use_dynamic_installenumnono | yes_prompt | yes_without_promptInstall missing extensions on demand.
extension.run_after_dynamic_installboolfalsetrue | falseRun the original command after a dynamic install completes.
extension.index_urlstring""URLPrivate extension index URL (overrides the public one).

Example config — a realistic file for a developer working in a single subscription and region:

ini
# ~/.azure/config
[core]
output = table
collect_telemetry = no
only_show_errors = yes
no_color = no

[logging]
enable_log_file = yes
log_dir = /home/alice/.azure/logs

[defaults]
group = MyResourceGroup
location = westus2

[extension]
use_dynamic_install = yes_without_prompt
run_after_dynamic_install = true

[cloud]
name = AzureCloud

Output: (none — file content)

Equivalent environment variables for a CI runner where you don't want to ship a config file:

bash
export AZURE_CORE_OUTPUT=json
export AZURE_CORE_ONLY_SHOW_ERRORS=true
export AZURE_CORE_COLLECT_TELEMETRY=false
export AZURE_DEFAULTS_GROUP=MyResourceGroup
export AZURE_DEFAULTS_LOCATION=westus2

Output: (none — exits 0 on success)

Authentication

az login establishes the credential context for every subsequent command. The CLI supports five distinct credential types — interactive browser, device-code (headless), service principal with secret, service principal with certificate, and managed identity — and the right one depends on where the CLI is running. Tokens are cached under ~/.azure/ and refreshed automatically until the refresh token expires.

bash
# Interactive — opens the system browser
az login

# Device code — for SSH sessions or browser-less hosts
az login --use-device-code

# Service principal (client secret)
az login --service-principal \
  --username 00000000-0000-0000-0000-000000000000 \
  --password "$AZURE_CLIENT_SECRET" \
  --tenant 11111111-1111-1111-1111-111111111111

# Service principal (certificate)
az login --service-principal \
  --username 00000000-0000-0000-0000-000000000000 \
  --password /home/alice/.azure/sp-cert.pem \
  --tenant 11111111-1111-1111-1111-111111111111

# Managed identity (system-assigned) — only inside Azure VMs / App Service
az login --identity

# Managed identity (user-assigned)
az login --identity --username 22222222-2222-2222-2222-222222222222

# Show the current credential
az account show --output table

Output:

sql
EnvironmentName    HomeTenantId                          IsDefault    Name                State    TenantId
-----------------  ------------------------------------  -----------  ------------------  -------  ------------------------------------
AzureCloud         11111111-1111-1111-1111-111111111111  True         Pay-As-You-Go       Enabled  11111111-1111-1111-1111-111111111111

az account — subscriptions, tenants, management groups

az account is the management surface for the identity-and-billing layer. A single Microsoft Entra principal often spans multiple subscriptions across one or more tenants, and many enterprises group those subscriptions into a hierarchy of management groups for centralized policy and RBAC. az account lists everything you can see, switches the active context, mints raw access tokens, and (with az account management-group and az account lock) reaches up into governance.

Subscriptions

A subscription is the billing and isolation boundary — every resource you create belongs to exactly one. az account list shows the cached set; az account set chooses one as the default for every subsequent command (it writes to ~/.azure/azureProfile.json, so the choice persists across shells).

bash
# Show every subscription this identity can see (table view)
az account list --output table

# Refresh the cached list after a new role assignment was granted
az account list --refresh

# Show the active context — sub + tenant + user
az account show

# Just the sub ID (for variable capture)
az account show --query id -o tsv

# Make a subscription the default — by display name or GUID
az account set --subscription "Pay-As-You-Go"
az account set --subscription 33333333-3333-3333-3333-333333333333

# Clear the default (forces every command to specify --subscription)
az account clear

Output:

sql
Name                CloudName    SubscriptionId                        TenantId                              State    IsDefault
------------------  -----------  ------------------------------------  ------------------------------------  -------  -----------
Pay-As-You-Go       AzureCloud   33333333-3333-3333-3333-333333333333  11111111-1111-1111-1111-111111111111  Enabled  True
Sandbox             AzureCloud   44444444-4444-4444-4444-444444444444  11111111-1111-1111-1111-111111111111  Enabled  False

Tenants

A tenant is the Microsoft Entra directory — every subscription belongs to exactly one. Use az account tenant list when an identity is a guest in multiple directories and you want to see every tenant you can sign into without leaving the current login session.

bash
# List every tenant this identity is a member or guest of
az account tenant list --output table

# Show the tenant ID for the active subscription
az account show --query tenantId -o tsv

# List subscriptions filtered to a single tenant
az account list --query "[?tenantId=='11111111-1111-1111-1111-111111111111']" -o table

Output:

diff
TenantId                              DisplayName       DefaultDomain
------------------------------------  ----------------  ------------------------
11111111-1111-1111-1111-111111111111  Contoso Ltd       contoso.onmicrosoft.com
55555555-5555-5555-5555-555555555555  Fabrikam Inc.     fabrikam.onmicrosoft.com

Access tokens

az account get-access-token mints a bearer token for the active credential, scoped to a chosen audience. Useful for one-off curl calls into APIs that don't have CLI coverage, and for scripting against Microsoft Graph / Key Vault / Storage when you don't want to bring in an SDK.

bash
# Default audience: ARM (management.azure.com)
az account get-access-token --query accessToken -o tsv

# Microsoft Graph
az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv

# Key Vault data plane
az account get-access-token --resource https://vault.azure.net --query accessToken -o tsv

# Use it with curl
TOKEN=$(az account get-access-token --resource https://graph.microsoft.com --query accessToken -o tsv)
curl -sH "Authorization: Bearer $TOKEN" "https://graph.microsoft.com/v1.0/me" | jq .userPrincipalName

Output:

perl
"alice@example.com"

Management groups

Management groups give you a hierarchy above subscriptions — policy assignments and RBAC role assignments on a management group cascade to every subscription beneath it. The root group is the tenant; below it you can build any tree shape (Microsoft caps the depth at 6 levels).

bash
# Enable management-group hierarchy for the current tenant (one-time, idempotent)
az account management-group create --name root --display-name "Tenant Root"

# Create a child group nested under another
az account management-group create --name engineering --display-name "Engineering" --parent root
az account management-group create --name eng-prod --display-name "Engineering — Prod" --parent engineering
az account management-group create --name eng-sandbox --display-name "Engineering — Sandbox" --parent engineering

# List every management group in the tenant
az account management-group list --output table

# Show one group's metadata
az account management-group show --name engineering --expand --recurse --output yaml

# Move a subscription into a group
az account management-group subscription add \
  --name eng-sandbox \
  --subscription 44444444-4444-4444-4444-444444444444

# Remove a subscription from a group (returns it to the parent)
az account management-group subscription remove \
  --name eng-sandbox \
  --subscription 44444444-4444-4444-4444-444444444444

# Rename / update
az account management-group update --name engineering --display-name "Engineering Org"

# Delete (empty groups only — move children out first)
az account management-group delete --name eng-sandbox

Output:

diff
Name         DisplayName            TenantId
-----------  ---------------------  ------------------------------------
root         Tenant Root            11111111-1111-1111-1111-111111111111
engineering  Engineering Org        11111111-1111-1111-1111-111111111111
eng-prod     Engineering — Prod     11111111-1111-1111-1111-111111111111
eng-sandbox  Engineering — Sandbox  11111111-1111-1111-1111-111111111111

Subscription-level locks

az account lock (alias for az lock filtered to subscription scope) prevents accidental deletes or modifications at the subscription level. CanNotDelete blocks deletion but allows changes; ReadOnly blocks any write. Locks cascade to child resources, so a CanNotDelete at the subscription protects everything.

bash
# Apply a delete lock on the active subscription
az account lock create \
  --name no-delete-prod \
  --lock-type CanNotDelete \
  --notes "Prod sub — break-glass change required"

# List locks on the active subscription
az account lock list --output table

# Remove a lock
az account lock delete --name no-delete-prod

Output:

lua
Name              Level           Notes
----------------  --------------  --------------------------------------
no-delete-prod    CanNotDelete    Prod subbreak-glass change required

az devops — Azure DevOps configuration & projects

The az devops, az repos, az pipelines, az boards, and az artifacts command groups all ship in the azure-devops extension — they are not in core az. Install once, then az devops login (which prompts for a Personal Access Token) authenticates you against an organization at https://dev.azure.com/<org>. After login, az devops configure --defaults lets you stop typing --organization and --project on every command — by far the biggest ergonomic win for DevOps scripting.

bash
# Install the extension (once per machine)
az extension add --name azure-devops
az extension show --name azure-devops --query version -o tsv

# Authenticate against an organization (PAT prompt on stdin)
echo "$AZDO_PAT" | az devops login --organization https://dev.azure.com/contoso

# Set defaults so subsequent commands don't need --organization / --project
az devops configure --defaults \
  organization=https://dev.azure.com/contoso \
  project=ContosoWebApp

# Show the current defaults
az devops configure --list

# Clear a single default
az devops configure --defaults project=''

# Log out (clears the cached PAT from the keyring)
az devops logout

Output:

ini
organization = https://dev.azure.com/contoso
project = ContosoWebApp

Projects

A project is the top-level container inside an organization — every repo, pipeline, board, and artifact feed lives inside exactly one. az devops project create/list/show/delete is enough for full lifecycle management; the four key settings to think about at creation time are visibility (private/public), the source-control type (git is universal — tfvc is legacy), the work-item process (Agile/Scrum/Basic/CMMI), and the description.

bash
# List every project in the configured org
az devops project list --output table

# Show one project's metadata
az devops project show --project ContosoWebApp

# Create a new project (private, Git, Agile process)
az devops project create \
  --name ContosoAPI \
  --description "Backend services for Contoso storefront" \
  --visibility private \
  --source-control git \
  --process Agile

# Update visibility or description
az devops project update --project ContosoAPI --description "Backend microservices" --visibility private

# Delete (irreversible — prompts for confirmation unless --yes)
az devops project delete --id $(az devops project show --project Sandbox --query id -o tsv) --yes

Output:

arduino
ID                                    Name           Visibility    Process
------------------------------------  -------------  ------------  --------
66666666-6666-6666-6666-666666666666  ContosoWebApp  private       Agile
77777777-7777-7777-7777-777777777777  ContosoAPI     private       Agile

Teams, service endpoints, security

Teams are sub-units inside a project that map to work-item areas and dashboards. Service endpoints are the connections to external systems (GitHub, Docker registries, Azure subscriptions for pipelines). Security uses az devops security (groups, permissions, namespaces).

bash
# List teams in the default project
az devops team list --output table

# Create a team and add members
az devops team create --name "Platform" --description "Platform engineering"
az devops user add --email-id alice@example.com --license-type express
az devops team add-member --team Platform --user alice@example.com

# Service endpoints — list and create a GitHub one
az devops service-endpoint list --output table
az devops service-endpoint github create \
  --name "github-contoso" \
  --github-url https://github.com/contoso/storefront

# Security groups in the project
az devops security group list --scope project --output table

Output:

sql
Name              Description
----------------  --------------------------
Contoso Team      The default project team
Platform          Platform engineering

az repos — repositories & pull requests

az repos covers the Git repositories that live inside an Azure DevOps project — create, list, import, set policies, and manage pull requests end-to-end. The most useful sub-groups are az repos (the Git repos themselves), az repos pr (pull requests with full review workflow), and az repos policy (branch policies — required reviewers, build validation, comment resolution).

Repositories

bash
# List every repo in the default project
az repos list --output table

# Show one repo's metadata (clone URLs, default branch)
az repos show --repository ContosoWeb --query "{name:name, defaultBranch:defaultBranch, remoteUrl:remoteUrl}"

# Create a new empty repo
az repos create --name ContosoMobile

# Import from an external Git URL (GitHub, GitLab, …)
az repos import create \
  --git-source-url https://github.com/contoso/legacy-app.git \
  --repository ContosoLegacy

# Rename
az repos update --repository ContosoMobile --default-branch refs/heads/main

# Delete (by ID — `az repos list` for the ID)
az repos delete --id $(az repos show --repository Throwaway --query id -o tsv) --yes

Output:

bash
Default Branch     ID                                    Name             Project        Size
-----------------  ------------------------------------  ---------------  -------------  --------
refs/heads/main    88888888-8888-8888-8888-888888888888  ContosoWeb       ContosoWebApp  4823920
refs/heads/main    99999999-9999-9999-9999-999999999999  ContosoLegacy    ContosoWebApp  1284560

Pull requests

az repos pr mirrors what you'd do in the browser: create, list, edit, approve, merge, and abandon PRs. Combined with --auto-complete it lets you queue a PR that merges itself once all required policies pass — the most common use case in CI-driven workflows.

bash
# Create a PR from a feature branch into main
az repos pr create \
  --repository ContosoWeb \
  --source-branch feature/login-refresh \
  --target-branch main \
  --title "Refresh login flow to use Entra B2C" \
  --description "Fixes #1284. Replaces legacy ASP.NET Identity with MSAL." \
  --reviewers alice@example.com bob@example.com \
  --work-items 1284 1287 \
  --draft false \
  --auto-complete true \
  --delete-source-branch true \
  --squash true

# List PRs (filter: active, mine, target=main)
az repos pr list --status active --creator alice@example.com --target-branch main --output table

# Show one PR
az repos pr show --id 4271 --query "{id:pullRequestId, title:title, status:status, mergeStatus:mergeStatus}"

# Add reviewers post-creation
az repos pr reviewer add --id 4271 --reviewers carol@example.com

# Vote: approve / approve-with-suggestions / wait / reject / reset
az repos pr set-vote --id 4271 --vote approve

# Add a comment
az repos pr work-item add --id 4271 --work-items 1290

# Complete (merge) manually
az repos pr update --id 4271 --status completed --merge-commit-message "Merged via az repos pr"

# Abandon
az repos pr update --id 4271 --status abandoned

Output:

yaml
ID    Created                           Title                                       Status   Vote
----  --------------------------------  ------------------------------------------  -------  ------
4271  2026-06-08T11:24:01.123456+00:00  Refresh login flow to use Entra B2C         active   waiting
4268  2026-06-07T16:02:14.987654+00:00  Bump @azure/identity to 4.5                 active   approved

Branch policies

Branch policies enforce quality gates on PRs targeting a protected branch — minimum reviewer count, build validation, work-item linking, comment resolution. az repos policy lets you script the same set of policies across every protected branch in every repo, which is the standard way enterprises maintain governance at scale.

bash
REPO_ID=$(az repos show --repository ContosoWeb --query id -o tsv)

# List every policy on a repo (or a specific branch)
az repos policy list --repository-id $REPO_ID --output table
az repos policy list --repository-id $REPO_ID --branch main --output table

# Require N approving reviewers
az repos policy approver-count create \
  --repository-id $REPO_ID \
  --branch main \
  --blocking true \
  --enabled true \
  --minimum-approver-count 2 \
  --creator-vote-counts false \
  --allow-downvotes false \
  --reset-on-source-push true

# Require build validation (pipeline must pass before merge)
PIPELINE_ID=$(az pipelines show --name contoso-web-ci --query id -o tsv)
az repos policy build create \
  --repository-id $REPO_ID \
  --branch main \
  --blocking true \
  --enabled true \
  --build-definition-id $PIPELINE_ID \
  --display-name "CI must pass" \
  --queue-on-source-update-only true \
  --manual-queue-only false \
  --valid-duration 1440

# Require all comments resolved
az repos policy comment-required create \
  --repository-id $REPO_ID \
  --branch main \
  --blocking true \
  --enabled true

# Require linked work items
az repos policy work-item-linking create \
  --repository-id $REPO_ID \
  --branch main \
  --blocking true \
  --enabled true

# Update a policy (toggle enabled/blocking)
az repos policy update --id 1421 --enabled false

# Delete
az repos policy delete --id 1421 --yes

Output:

yaml
ID    Name                          Is Blocking    Is Enabled    Branch
----  ----------------------------  -------------  ------------  -----------------
1418  Minimum number of reviewers   True           True          refs/heads/main
1421  Build (CI must pass)          True           True          refs/heads/main
1424  Comment requirements          True           True          refs/heads/main
1427  Work item linking             True           True          refs/heads/main

az pipelines — build & release pipelines

az pipelines is the build/release pipeline surface — YAML pipelines and the older Classic UI-defined ones both work here. The day-to-day sub-groups are az pipelines itself (create, run, show, list, delete pipelines), az pipelines runs (queue/show/list/cancel runs), az pipelines variable and az pipelines variable-group (build-time variables, individual and shared), az pipelines agent / az pipelines pool (self-hosted agent management), and az pipelines release (Classic releases — being deprecated in favor of multi-stage YAML).

Creating and listing pipelines

bash
# Create a YAML pipeline tied to a repo file (auto-runs once on creation)
az pipelines create \
  --name "contoso-web-ci" \
  --description "Build, test, deploy ContosoWeb" \
  --repository ContosoWeb \
  --repository-type tfsgit \
  --branch main \
  --yaml-path .azure-pipelines/ci.yml

# Create from a YAML file in an external GitHub repo
az pipelines create \
  --name "contoso-mobile-ci" \
  --repository contoso/mobile \
  --repository-type github \
  --service-connection $(az devops service-endpoint list --query "[?name=='github-contoso'].id | [0]" -o tsv) \
  --branch main \
  --yaml-path azure-pipelines.yml

# List all pipelines in the default project
az pipelines list --output table

# Show one pipeline (definition)
az pipelines show --name contoso-web-ci --query "{name:name, queue:queue.name, branch:repository.defaultBranch}"

# Update branch or YAML path
az pipelines update --name contoso-web-ci --new-name contoso-web-ci-v2 --branch release/v2

# Delete
az pipelines delete --name contoso-web-ci-v2 --yes

Output:

bash
ID    Name              Type    Repository
----  ----------------  ------  ------------
12    contoso-web-ci    build   ContosoWeb
13    contoso-mobile    build   contoso/mobile

Pipeline runs

az pipelines runs queues a build and surfaces every state transition. Combine with --parameters to pass runtime template parameters and --variables to set/override build variables for a single run — useful for promoting the same pipeline across dev/staging/prod from one definition.

bash
# Queue a run on the default branch
az pipelines run --name contoso-web-ci --branch main

# Run with parameters + variables + a specific commit
az pipelines run \
  --name contoso-web-ci \
  --branch main \
  --commit-id 3f2c91a4e8b7d1c9a0f4e6b8c2d1a3f5e7b9c4d6 \
  --parameters environment=staging deployRegion=westus2 \
  --variables DEPLOY_TARGET=staging API_KEY=$STAGING_API_KEY \
  --open

# List recent runs (filter by pipeline, status, branch, top N)
az pipelines runs list \
  --pipeline-ids 12 \
  --branch main \
  --status completed \
  --result succeeded \
  --top 10 \
  --output table

# Show a single run
az pipelines runs show --id 8842 --query "{id:id, status:status, result:result, branch:sourceBranch}"

# Cancel a running build
az pipelines runs update --id 8842 --status cancelling

# Tag a run for downstream filtering
az pipelines runs tag add --run-id 8842 --tags release-candidate v2.3.1

# List artifacts produced by a run
az pipelines runs artifact list --run-id 8842 --output table

# Download an artifact
az pipelines runs artifact download \
  --run-id 8842 \
  --artifact-name drop \
  --path ./build-output

Output:

yaml
Run ID    Number             Status       Result     Pipeline ID    Pipeline Name      Source Branch        Queued Time
--------  -----------------  -----------  ---------  -------------  -----------------  -------------------  --------------------------------
8842      20260608.4         completed    succeeded  12             contoso-web-ci     refs/heads/main      2026-06-08T14:30:02.123+00:00
8841      20260608.3         completed    failed     12             contoso-web-ci     refs/heads/feat-x    2026-06-08T13:11:45.987+00:00

Variables and variable groups

Individual pipeline variables live on a single pipeline definition; variable groups are shared across multiple pipelines (and optionally backed by an Azure Key Vault). Secrets in either are write-only via the CLI — you can update or rotate them, but you can't read the cleartext back.

bash
PID=$(az pipelines show --name contoso-web-ci --query id -o tsv)

# Add a plain variable to a pipeline
az pipelines variable create \
  --pipeline-id $PID \
  --name DEPLOY_TARGET \
  --value staging \
  --allow-override true

# Add a secret variable
az pipelines variable create \
  --pipeline-id $PID \
  --name API_KEY \
  --value "$REAL_SECRET_VALUE" \
  --secret true \
  --allow-override false

# List variables on a pipeline
az pipelines variable list --pipeline-id $PID --output table

# Update a variable (or rotate a secret)
az pipelines variable update --pipeline-id $PID --name API_KEY --value "$NEW_SECRET" --secret true

# Delete
az pipelines variable delete --pipeline-id $PID --name DEPLOY_TARGET --yes

# Create a variable group (shared across pipelines)
az pipelines variable-group create \
  --name contoso-shared \
  --description "Shared deploy settings" \
  --authorize true \
  --variables REGION=westus2 STORAGE_ACCOUNT=alicedev01

# Add a Key-Vault-backed variable group
SP_ID=$(az devops service-endpoint list --query "[?name=='azure-contoso'].id | [0]" -o tsv)
az pipelines variable-group create \
  --name contoso-kv \
  --description "Secrets from Key Vault" \
  --authorize true \
  --variables KV_PLACEHOLDER=ignored

# Link / unlink variables in a group
az pipelines variable-group variable create --group-id 14 --name DB_USER --value alicedev
az pipelines variable-group variable update --group-id 14 --name DB_USER --value bobdev
az pipelines variable-group variable delete --group-id 14 --name DB_USER --yes

# List all groups
az pipelines variable-group list --output table

Output:

sql
Name              Allow Override    Is Secret    Value
----------------  ----------------  -----------  --------
DEPLOY_TARGET     True              False        staging
API_KEY           False             True         ***

Agents and pools

Microsoft-hosted agents are the default — pools like Azure Pipelines and ubuntu-latest are pre-provisioned. Self-hosted pools are for organizations with build hosts that need access to private networks, custom toolchains, or GPUs. az pipelines pool and az pipelines agent cover the read side; agent registration itself happens via the agent installer, not the CLI.

bash
# List every agent pool in the org
az pipelines pool list --output table

# Show one pool
az pipelines pool show --pool-name "Default" --query "{name:name, isHosted:isHosted, size:size}"

# List agents in a pool
az pipelines agent list --pool-id 5 --output table

# Show one agent's status
az pipelines agent show --pool-id 5 --agent-id 27 --query "{name:name, status:status, version:version, online:enabled}"

Output:

sql
ID    Name            Is Hosted    Pool Type
----  --------------  -----------  -----------
1     Azure Pipelines True         automation
5     Default         False        automation

Releases (Classic)

Classic release pipelines are being superseded by multi-stage YAML pipelines, but a huge installed base remains. az pipelines release covers create-definition / list / show / cancel; for new work, prefer YAML pipelines with environments and approval gates.

bash
# List release definitions
az pipelines release definition list --output table

# Trigger a release
az pipelines release create --definition-id 7 --description "Manual prod release"

# List releases
az pipelines release list --definition-id 7 --top 5 --output table

# Show a single release
az pipelines release show --id 84 --query "{name:name, status:status, environments:environments[].name}"

Output:

sql
Name              ID    Status     Created On                       Created By
----------------  ----  ---------  -------------------------------  --------------------
Release-84        84    active     2026-06-08T15:02:11+00:00        alice@example.com
Release-83        83    completed  2026-06-07T09:14:33+00:00        bob@example.com

Resource groups and resources

Resource groups are the unit of lifecycle management in Azure — every resource lives in exactly one group, and deleting the group deletes everything inside. The az group and az resource command groups together give you the generic create/list/move/delete surface that maps directly to the Azure Resource Manager API.

bash
# Create a new RG in West US 2
az group create --name MyResourceGroup --location westus2

# List groups (table format)
az group list --output table

# Show one group's metadata
az group show --name MyResourceGroup

# List every resource inside a group
az resource list --resource-group MyResourceGroup --output table

# Tag a group (or any resource)
az group update --name MyResourceGroup --tags owner=alicedev env=dev

# Move a resource between groups (same subscription)
az resource move --destination-group MyResourceGroup-prod \
  --ids $(az resource show -g MyResourceGroup -n mystorage --resource-type Microsoft.Storage/storageAccounts --query id -o tsv)

# Delete an RG and everything in it (no confirmation in CI)
az group delete --name MyResourceGroup --yes --no-wait

Output:

diff
Name              Location    Status
----------------  ----------  ---------
MyResourceGroup   westus2     Succeeded

Output formatting and JMESPath queries

--output controls the serializer; --query runs a JMESPath expression against the response before serialization. Together they replace ad-hoc jq pipelines for almost everything — the query runs client-side after the API returns, so it doesn't reduce the request payload, but it makes scripts much easier to read.

bash
# Default: JSON
az vm list

# Table — flattens common columns
az vm list --output table

# TSV — perfect for `read` / `awk` / `cut`
az vm list --query "[].name" --output tsv

# Project specific fields
az vm list --query "[].{name:name, size:hardwareProfile.vmSize, os:storageProfile.osDisk.osType}" \
  --output table

# Filter by tag
az vm list --query "[?tags.env=='prod'].name" --output tsv

# Get the first hit
az vm list --query "[0].name" --output tsv

# Chain: get the public IP of a VM by name
az vm list-ip-addresses --name myvm \
  --query "[].virtualMachine.network.publicIpAddresses[0].ipAddress" -o tsv

Output:

diff
Name        ResourceGroup     Location   Zones
----------  ----------------  ---------  -----
myvm        MyResourceGroup   westus2
appserver   MyResourceGroup   westus2    1

Extensions

Most newer or preview Azure services ship as CLI extensions rather than in the core binary. They live under ~/.azure/cliextensions/<name> and are managed with az extension. Set extension.use_dynamic_install = yes_without_prompt once and the CLI will install missing extensions on demand the first time you invoke a command that needs them.

bash
# List installed extensions
az extension list --output table

# Search for extensions matching a name
az extension list-available --output table | grep -i bastion

# Add an extension
az extension add --name azure-devops
az extension add --name containerapp

# Update one (or all)
az extension update --name azure-devops
az extension list --query "[].name" -o tsv | xargs -n1 az extension update --name

# Remove
az extension remove --name azure-devops

# Use a private index
az config set extension.index_url=https://myhost/internal/index.json

Output:

sql
Name           Version    Preview    Experimental    ExtensionType
-------------  ---------  ---------  --------------  ---------------
azure-devops   1.0.4      False      False           whl
containerapp   1.1.0      False      False           whl

Long-running operations and --no-wait

Many Azure operations (VM creation, AKS cluster provisioning, role assignment propagation) are asynchronous — ARM returns a 202 with a status URL and the CLI polls it until success or failure. --no-wait short-circuits the polling so your script can fire-and-forget, then use az resource wait or service-specific wait sub-commands to synchronize at a later checkpoint.

bash
# Fire off a VM creation and move on
az vm create \
  --resource-group MyResourceGroup \
  --name appserver \
  --image Ubuntu2204 \
  --admin-username alicedev \
  --generate-ssh-keys \
  --no-wait

# Block until it reaches a terminal state
az vm wait --resource-group MyResourceGroup --name appserver --created --timeout 600

# Generic wait — any resource type, any condition expressed as JMESPath
az resource wait \
  --ids $(az vm show -g MyResourceGroup -n appserver --query id -o tsv) \
  --custom "provisioningState=='Succeeded'" \
  --interval 10 --timeout 600

Output:

json
{
  "fqdns": "",
  "id": "/subscriptions/33333333-.../resourceGroups/MyResourceGroup/providers/Microsoft.Compute/virtualMachines/appserver",
  "powerState": "VM running",
  "publicIpAddress": "20.55.12.34",
  "resourceGroup": "MyResourceGroup",
  "zones": ""
}

Generic REST calls with az rest

When a service is too new to have CLI coverage, or when you need an obscure ARM endpoint, az rest reuses your existing authentication context and signs an arbitrary HTTPS request. It's the escape hatch that means you almost never need to mint a token manually with az account get-access-token and call curl.

bash
# GET a single resource by ID
az rest --method get \
  --uri "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/MyResourceGroup?api-version=2024-03-01"

# GET against Microsoft Graph (changes the audience automatically)
az rest --method get --uri "https://graph.microsoft.com/v1.0/me"

# POST with a body
az rest --method post \
  --uri "https://management.azure.com/subscriptions/$(az account show --query id -o tsv)/providers/Microsoft.ResourceGraph/resources?api-version=2022-10-01" \
  --body '{"subscriptions":["33333333-3333-3333-3333-333333333333"],"query":"Resources | project name, type, location"}' \
  --headers Content-Type=application/json

Output:

json
{
  "id": "/subscriptions/33333333-.../resourceGroups/MyResourceGroup",
  "location": "westus2",
  "name": "MyResourceGroup",
  "properties": {"provisioningState": "Succeeded"},
  "tags": {"env": "dev"},
  "type": "Microsoft.Resources/resourceGroups"
}

ARM and Bicep deployments

az deployment is the imperative wrapper around Azure Resource Manager template deployments. You can submit either a JSON ARM template or a Bicep file (the CLI compiles it on the fly when you have the Bicep tool installed). The four scope flags — group, sub, mg, tenant — pick which scope the deployment runs at.

bash
# Validate before deploying
az deployment group validate \
  --resource-group MyResourceGroup \
  --template-file ./main.bicep \
  --parameters env=dev sku=Standard_LRS

# What-if (preview the diff)
az deployment group what-if \
  --resource-group MyResourceGroup \
  --template-file ./main.bicep

# Deploy
az deployment group create \
  --name infra-$(date +%Y%m%d-%H%M) \
  --resource-group MyResourceGroup \
  --template-file ./main.bicep \
  --parameters @./params.json

# Subscription-scope deployment (creates the RG itself, etc.)
az deployment sub create \
  --name bootstrap \
  --location westus2 \
  --template-file ./bootstrap.bicep

# List recent deployments
az deployment group list --resource-group MyResourceGroup --output table

Output:

sql
Name              State      Timestamp                         Mode
----------------  ---------  --------------------------------  ----------
infra-20260608    Succeeded  2026-06-08T14:21:00.123456+00:00  Incremental

Common pitfalls

  1. Forgetting --output tsv for variable capture — JSON output is wrapped in quotes ("westus2") and breaks $() interpolation. Use --output tsv (or -o tsv) for any value you intend to pass to another command.
  2. JMESPath --query after API call, not before--query runs locally, so it doesn't reduce server-side load. For huge lists, use server-side filters like az resource list --resource-group … --resource-type … first, then --query.
  3. az login opens a browser by default — on a headless VM/SSH session this dumps an error about xdg-open; use --use-device-code or service principal auth instead.
  4. Service-principal credentials in --password leak into shell history — read from an env var or a file (--password $AZURE_CLIENT_SECRET, --password /path/to/secret) and treat the file as a secret.
  5. Default subscription is per-machine, not per-shellaz account set writes to ~/.azure/azureProfile.json and affects every shell. For per-script overrides, pass --subscription on every command.
  6. Confirmation prompts hang CI — set core.disable_confirm_prompt = yes in config or pass --yes on each destructive command. Preview warnings can still appear on stderr; silence them with --only-show-errors or core.only_show_errors = yes.
  7. Long-running operations block by defaultaz vm create returns only after the VM is fully provisioned (~2 minutes). Use --no-wait plus az resource wait if you have more work to do in parallel.
  8. Extensions and core can drift — after az upgrade, run az extension update --name <each> (or list-pipe-update). Stale extensions cause cryptic auth or schema errors against current ARM API versions.
  9. az config set does not validate keys — typos like core.outputt are silently accepted and have no effect. Round-trip with az config get core.outputt after setting to confirm.
  10. WSL az login can't open the Windows browser without WSLU — install wslu or pass --use-device-code. Tokens then cache in the WSL filesystem, not the Windows side.
  11. az devops commands silently use stale defaultsaz devops configure --defaults project=ContosoOld lingers across shells. Run az devops configure --list whenever a repos/pipelines command targets a project you don't expect.
  12. PAT vs az login confusionaz devops login uses a Personal Access Token (PAT) scoped to a single org, while core az login uses Microsoft Entra. Some az devops / az repos / az pipelines calls fall back to the Entra token automatically (--detect); explicit PAT login is more predictable in CI.
  13. az pipelines run --variables only overrides variables marked allow-override — set --allow-override true at create time or the runtime value is ignored without an error.
  14. Secret variables can't be read backaz pipelines variable list shows secrets as ***. To rotate, az pipelines variable update --secret true --value $NEW. To "view" one, dump it from a pipeline step (with isOutput=true and a ${{ }} reference) — never in cleartext logs.
  15. Subscription locks block management-group moves too — a ReadOnly lock on a subscription prevents az account management-group subscription add from succeeding. Remove the lock, move, re-apply.

Real-world recipes

Create a resource group, storage account, and upload a blob

End-to-end provisioning of a storage account with RBAC-only access plus uploading a file — the typical "land some data in Azure" pipeline.

bash
RG=MyResourceGroup
LOC=westus2
SA=alicedev$(openssl rand -hex 3)
CONTAINER=data

az group create -n "$RG" -l "$LOC"
az storage account create -n "$SA" -g "$RG" -l "$LOC" --sku Standard_LRS --allow-blob-public-access false

az storage container create \
  --account-name "$SA" \
  --name "$CONTAINER" \
  --auth-mode login

az storage blob upload \
  --account-name "$SA" \
  --container-name "$CONTAINER" \
  --name report.csv \
  --file ./report.csv \
  --auth-mode login

az storage blob list --account-name "$SA" --container-name "$CONTAINER" --auth-mode login -o table

Output:

sql
Name        Blob Type    Blob Tier    Length    Content Type    Last Modified
----------  -----------  -----------  --------  --------------  -------------------------
report.csv  BlockBlob    Hot          12431     text/csv        2026-06-08T14:22:11+00:00

Tear down everything tagged env=sandbox

A weekly sweeper for sandbox resources — uses --query to filter and xargs to fan out into az group delete calls.

bash
az group list --query "[?tags.env=='sandbox'].name" -o tsv \
  | xargs -I {} az group delete --name {} --yes --no-wait

echo "Deletion requested for every sandbox RG."

Output:

rust
Deletion requested for every sandbox RG.

Service-principal-driven deployment in GitHub Actions

Login non-interactively, deploy a Bicep file, and assert success — all using environment variables passed in as Actions secrets.

bash
az login --service-principal \
  --username  "$AZURE_CLIENT_ID" \
  --password  "$AZURE_CLIENT_SECRET" \
  --tenant    "$AZURE_TENANT_ID" \
  --only-show-errors

az account set --subscription "$AZURE_SUBSCRIPTION_ID"

az deployment group create \
  --name "ci-$GITHUB_RUN_NUMBER" \
  --resource-group MyResourceGroup \
  --template-file ./infra/main.bicep \
  --parameters @./infra/params.json \
  --query "properties.provisioningState" -o tsv

Output:

code
Succeeded

Cost: list every VM with its size and OS

A snapshot for an inventory spreadsheet — combine --query projections with --output tsv and pipe straight into a CSV file.

bash
echo "name,resource_group,size,os,location" > vms.csv
az vm list \
  --query "[].{name:name, rg:resourceGroup, size:hardwareProfile.vmSize, os:storageProfile.osDisk.osType, loc:location}" \
  -o tsv \
  | awk -F'\t' '{print $1","$2","$3","$4","$5}' >> vms.csv

head -3 vms.csv

Output:

arduino
name,resource_group,size,os,location
appserver,MyResourceGroup,Standard_D2s_v3,Linux,westus2
db-01,MyResourceGroup,Standard_E4s_v3,Linux,westus2

Diagnose an ARM 4xx with --debug

When a command fails with a vague error, --debug dumps the full HTTP request URL, headers, body, and the ARM error payload — that's almost always enough to identify a missing role assignment, a quota issue, or a malformed property.

bash
az vm create \
  -g MyResourceGroup -n badvm \
  --image Ubuntu2204 --size Standard_NOPE \
  --admin-username alicedev --generate-ssh-keys \
  --debug 2>&1 \
  | grep -E "(Request URL|Response status|error|InvalidParameter)" \
  | head

Output:

arduino
cli.azure.cli.core.sdk.policies: Request URL: 'https://management.azure.com/subscriptions/.../providers/Microsoft.Compute/locations/westus2/vmSizes?api-version=2024-07-01'
cli.azure.cli.core.sdk.policies: Response status: 200
cli.azure.cli.core.sdk.policies: Request URL: 'https://management.azure.com/.../providers/Microsoft.Compute/virtualMachines/badvm?api-version=2024-07-01'
cli.azure.cli.core.sdk.policies: Response status: 400
cli.azure.cli.core.azclierror: The provided VM size 'Standard_NOPE' is not available...

Switch sovereign clouds (commercial → Azure US Government)

When working with a customer on a regulated tenant, point the CLI at a different sovereign cloud — every subsequent call routes to the gov endpoints (management.usgovcloudapi.net, etc.).

bash
az cloud list --output table
az cloud set --name AzureUSGovernment
az login
az account show --query "environmentName" -o tsv

Output:

code
AzureUSGovernment

Bootstrap a project + repo + CI pipeline + branch policies

Spin up an Azure DevOps project from scratch, import a Git repo, create a YAML pipeline, and apply the standard branch-policy gates (2 reviewers + build validation + comments resolved) in one script. The kind of thing you copy once and reuse on every new microservice.

bash
ORG=https://dev.azure.com/contoso
PROJ=ContosoAPI
REPO_NAME=storefront-svc
PIPE_NAME=storefront-svc-ci

az devops configure --defaults organization=$ORG project=$PROJ

az devops project create --name "$PROJ" --visibility private --source-control git --process Agile

az repos import create \
  --git-source-url https://github.com/contoso/storefront-svc.git \
  --repository "$REPO_NAME"

REPO_ID=$(az repos show --repository "$REPO_NAME" --query id -o tsv)

az pipelines create \
  --name "$PIPE_NAME" \
  --repository "$REPO_NAME" \
  --repository-type tfsgit \
  --branch main \
  --yaml-path .azure-pipelines/ci.yml

PIPE_ID=$(az pipelines show --name "$PIPE_NAME" --query id -o tsv)

az repos policy approver-count create --repository-id $REPO_ID --branch main \
  --blocking true --enabled true --minimum-approver-count 2 \
  --creator-vote-counts false --allow-downvotes false --reset-on-source-push true

az repos policy build create --repository-id $REPO_ID --branch main \
  --blocking true --enabled true --build-definition-id $PIPE_ID \
  --display-name "CI must pass" --queue-on-source-update-only true \
  --manual-queue-only false --valid-duration 1440

az repos policy comment-required create --repository-id $REPO_ID --branch main \
  --blocking true --enabled true

echo "Bootstrap complete for $PROJ/$REPO_NAME — pipeline $PIPE_NAME (#$PIPE_ID)"

Output:

bash
Bootstrap complete for ContosoAPI/storefront-svc — pipeline storefront-svc-ci (#42)

Promote a release through dev → staging → prod

Run the same CI pipeline three times against the same commit, each with a different environment parameter and matching variable group — the canonical "manual promotion" flow when you don't yet have multi-stage YAML approvals wired up.

bash
PIPE_NAME=storefront-svc-ci
COMMIT=$(git rev-parse main)

for ENV in dev staging prod; do
  RUN_ID=$(az pipelines run \
    --name "$PIPE_NAME" \
    --branch main \
    --commit-id "$COMMIT" \
    --parameters environment=$ENV \
    --variables DEPLOY_TARGET=$ENV \
    --query id -o tsv)

  echo "Queued $ENV deploy as run #$RUN_ID — waiting for success"

  for i in $(seq 1 60); do
    STATUS=$(az pipelines runs show --id $RUN_ID --query "{s:status, r:result}" -o tsv)
    case "$STATUS" in
      "completed	succeeded") echo "  → $ENV succeeded"; break ;;
      "completed	"*)         echo "  → $ENV failed: $STATUS"; exit 1 ;;
      *)                       sleep 15 ;;
    esac
  done
done

Output:

csharp
Queued dev deploy as run #8851 — waiting for success
  → dev succeeded
Queued staging deploy as run #8852 — waiting for success
  → staging succeeded
Queued prod deploy as run #8853 — waiting for success
  → prod succeeded

Audit every PR open longer than 7 days across all repos

A weekly hygiene sweep — list active PRs by age and post a Slack-ready summary. Combines az repos list to fan out across repos with az repos pr list per repo, then jq to filter and format.

bash
THRESHOLD_DAYS=7
NOW=$(date -u +%s)

az repos list --query "[].id" -o tsv | while read REPO_ID; do
  az repos pr list --status active --repository "$REPO_ID" \
    --query "[].{id:pullRequestId, title:title, creator:createdBy.uniqueName, created:creationDate}" \
    -o json
done | jq -s --argjson now "$NOW" --argjson th "$THRESHOLD_DAYS" '
  add
  | map(. + {ageDays: (($now - (.created | sub("\\.\\d+"; "") | fromdateiso8601)) / 86400 | floor)})
  | map(select(.ageDays >= $th))
  | sort_by(-.ageDays)
  | .[] | "\(.ageDays)d  #\(.id)  \(.creator)  \(.title)"'

Output:

ruby
14d  #4189  bob@example.com  Refactor auth middleware
11d  #4203  alice@example.com  Add metrics for cold-start latency
8d   #4231  carol@example.com  Bump @azure/identity to 4.5

Tail Activity Log for a single resource group

When something just deleted itself, this is the first place to look. --max-events keeps the request small and --query flattens the payload to the columns that matter for a quick scan.

bash
az monitor activity-log list \
  --resource-group MyResourceGroup \
  --max-events 30 \
  --query "[].{time:eventTimestamp, op:operationName.localizedValue, caller:caller, status:status.value}" \
  -o table

Output:

sql
Time                              Op                                            Caller                State
--------------------------------  --------------------------------------------  --------------------  ---------
2026-06-08T14:33:11.123456+00:00  Delete Storage Account                        alicedev@example.com  Succeeded
2026-06-08T14:30:02.987654+00:00  Update Resource Group                         alicedev@example.com  Succeeded

Sources

References consulted while writing this article. Links open in a new tab.

  • Azure CLI release notes — Confirmed the current stable version (2.87.0, June 2026) and upcoming 2.88.0 / 2.89.0 schedule cited in What it is and Install.
  • Azure CLI configuration options — Source for the full [core]/[logging]/[defaults]/[storage]/[cloud]/[batch]/[extension] option tables and the AZURE_{SECTION}_{KEY} environment-variable pattern.
  • Install the Azure CLI — Provided the canonical apt/dnf/brew/winget/pip install commands and the aka.ms/InstallAzureCLIDeb one-liner.
  • Sign in with the Azure CLI — Authoritative list of the five credential types (interactive, device code, service principal with secret, service principal with cert, managed identity) used in Authentication.
  • Sign in with a service principal — Exact flag shape (--service-principal --username … --password … --tenant …) used in the CI recipe.
  • Upcoming breaking changes — Confirmed 2.87.0 breaking changes (e.g. --access-keys-auth default flip) referenced in What it is.
  • Azure/azure-cli on GitHub — Canonical repository; release tags, issue tracker, and Python source.
  • Manage Azure subscriptions with the Azure CLI — Source for az account list/set/clear semantics and the --refresh flag used in the az account section.
  • az account management-group reference — Exact create/list/show/update/delete and the nested subscription add/remove sub-group used to build the hierarchy example.
  • Get started with Azure DevOps CLI — Established that az devops/az repos/az pipelines ship in the azure-devops extension and require az devops login with a PAT.
  • azure-devops-cli-extension getting started — Provided the az devops configure --defaults organization=… project=… ergonomic pattern.
  • Manage pipelines with the Azure DevOps CLI — Source for az pipelines create / run / runs / runs artifact patterns and the YAML-pipeline-from-repo example.
  • az pipelines variable reference — Flag shape for --secret, --allow-override, and the rotation-vs-read constraint cited in Common pitfalls.
  • az repos pr reference — Full flag list for az repos pr create (auto-complete, reviewers, work-items, squash, delete-source-branch).
  • az repos pr policy reference — Source for approver-count / build / comment-required / work-item-linking branch-policy commands and their flag combinations.