Home / AI & GenAI

AI & GenAICheat sheetBeginner

Azure OpenAI CLI cheat sheet: accounts, deployments, quota, keys, metrics and logs

The az commands, test calls, metric names and KQL you need day to day for Azure OpenAI - from listing deployments and quota to keys, network rules and diagnostic logs.

Deepak Bhardwaj8 min read

Applies toAzure OpenAI in Microsoft Foundry Models (kind OpenAI and AIServices accounts); Azure CLI 2.6x and later; Log Analytics

You are on call, an app team says "Azure OpenAI is broken", and you need answers fast: which deployments exist, what model version they run, how much quota is left, whether keys are enabled, and what the metrics say. This page collects the commands for those checks in one place.

Set these once per shell session:

RG=rg-ai-prod
ACCT=aoai-prod-swc
LOC=swedencentral
ID=$(az cognitiveservices account show -g $RG -n $ACCT --query id -o tsv)

Tip

Some newer subcommands (cost controls, agents, managed networks) come from preview extensions or recent CLI releases. Run az version and az upgrade if a command in this page is missing.

Accounts

# All Azure OpenAI and AI Services accounts in the subscription
az cognitiveservices account list \
  --query "[?kind=='OpenAI' || kind=='AIServices'].{name:name, rg:resourceGroup, kind:kind, location:location}" -o table

# Endpoint, network and auth settings for one account
az cognitiveservices account show -g $RG -n $ACCT \
  --query "{endpoint:properties.endpoint, publicAccess:properties.publicNetworkAccess, localAuthDisabled:properties.disableLocalAuth, customDomain:properties.customSubDomainName}"

Soft-deleted accounts

A deleted account stays soft-deleted for a retention period and holds its name. If someone deleted the wrong one, recover it before you redeploy anything.

az cognitiveservices account list-deleted -o table
az cognitiveservices account recover -g $RG -n $ACCT -l $LOC

Caution

az cognitiveservices account purge removes a soft-deleted account permanently, including its deployments. Only purge when you are sure nothing needs to be recovered.

Deployments

# What is deployed: model, version, SKU (deployment type), capacity, upgrade policy
az cognitiveservices account deployment list -g $RG -n $ACCT \
  --query "[].{deployment:name, model:properties.model.name, version:properties.model.version, sku:sku.name, capacity:sku.capacity, upgrade:properties.versionUpgradeOption, state:properties.provisioningState}" -o table

# Full detail for one deployment, including rate limits
az cognitiveservices account deployment show -g $RG -n $ACCT --deployment-name chat-prod

The sku.name value is the deployment type (Standard, GlobalStandard, DataZoneStandard, ProvisionedManaged and so on). For token-based SKUs, sku.capacity is in units of 1,000 tokens per minute; for provisioned SKUs it is PTUs.

Create or delete a deployment

az cognitiveservices account deployment create -g $RG -n $ACCT \
  --deployment-name chat-canary \
  --model-format OpenAI --model-name gpt-4.1 --model-version 2025-04-14 \
  --sku-name GlobalStandard --sku-capacity 50

az cognitiveservices account deployment delete -g $RG -n $ACCT --deployment-name chat-canary

Model names and versions available to you depend on region and account; take them from the list commands below rather than from memory. Provisioned deployments can use --spillover-deployment-name to send overflow to a standard deployment.

Warning

Deleting a deployment breaks every app that calls it immediately. Search your app config for the deployment name first, and check the AzureOpenAIRequests metric for that deployment over the last 24 hours.

Models and quota

# Models this account can deploy, with lifecycle and deprecation dates
az cognitiveservices account list-models -g $RG -n $ACCT \
  --query "[?format=='OpenAI'].{model:name, version:version, lifecycle:lifecycleStatus, retire:deprecation.inference}" -o table

# Models offered in a region
az cognitiveservices model list -l $LOC \
  --query "[?model.format=='OpenAI'].{model:model.name, version:model.version, kind:kind}" -o table

# Quota per region: used vs limit for each model and deployment type
az cognitiveservices usage list -l $LOC \
  --query "[?currentValue > \`0\`].{quota:name.value, used:currentValue, limit:limit}" -o table

Quota names look like OpenAI.GlobalStandard.gpt-4.1; the exact format varies by deployment type, so check your output. Quota is per subscription and region, so two accounts in the same region share it.

Keys and Entra ID

# Show keys (only if local auth is enabled)
az cognitiveservices account keys list -g $RG -n $ACCT

# Regenerate one key; apps on the other key keep working
az cognitiveservices account keys regenerate -g $RG -n $ACCT --key-name key2

# Disable key auth so only Entra ID tokens work
az resource update --ids $ID --set properties.disableLocalAuth=true

Caution

Setting disableLocalAuth=true breaks every client still using an api-key header. Confirm in the logs that no key-based calls remain before you switch it.

Role assignments for an app's managed identity:

az role assignment create --assignee <principal-id> \
  --role "Cognitive Services OpenAI User" --scope $ID

az role assignment list --scope $ID \
  --query "[].{who:principalName, role:roleDefinitionName}" -o table

Network rules

az cognitiveservices account network-rule list -g $RG -n $ACCT
az cognitiveservices account network-rule add -g $RG -n $ACCT --ip-address 203.0.113.10
az cognitiveservices account network-rule remove -g $RG -n $ACCT --ip-address 203.0.113.10

# Private endpoints attached to the account
az network private-endpoint-connection list --id $ID \
  --query "[].{name:name, status:properties.privateLinkServiceConnectionState.status}" -o table

Test call from the shell

This confirms that DNS, network, auth and the deployment all work, independent of the app.

ENDPOINT=$(az cognitiveservices account show -g $RG -n $ACCT --query properties.endpoint -o tsv)
TOKEN=$(az account get-access-token --resource https://cognitiveservices.azure.com --query accessToken -o tsv)

curl -sS -i "${ENDPOINT}openai/deployments/chat-prod/chat/completions?api-version=2024-10-21" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"Reply with OK"}],"max_tokens":5}'

Look at the status code and the x-ratelimit-remaining-tokens and x-ratelimit-remaining-requests headers. Your identity needs a data-plane role such as Cognitive Services OpenAI User; Owner or Contributor alone is not enough for token-based calls.

Response Likely cause First check
401 Wrong token audience, expired key, or local auth disabled disableLocalAuth, token --resource value
403 Network rules or private endpoint only, or missing data-plane role publicNetworkAccess, role assignments
404 DeploymentNotFound Deployment name typo or deployment deleted deployment list
429 Deployment TPM/RPM or PTU utilisation exhausted AzureOpenAIRequests by StatusCode, PTU utilisation
400 content_filter Content filter blocked prompt or output RAIRejectedRequests metric

Metrics

Use the Azure OpenAI metrics, not the legacy Cognitive Services ones such as Latency, TotalCalls or ClientErrors.

Question Metric Useful dimensions
Requests and errors AzureOpenAIRequests ModelDeploymentName, StatusCode, IsSpillover
Input / output tokens ProcessedPromptTokens, GeneratedTokens ModelDeploymentName
Total tokens TokenTransaction ModelDeploymentName
PTU usage AzureOpenAIProvisionedManagedUtilizationV2 ModelDeploymentName
Latency AzureOpenAITimeToResponse, AzureOpenAITTLTInMS ModelDeploymentName
Content filter blocks RAIRejectedRequests ModelDeploymentName, Category
# Requests per deployment and status code, 5-minute buckets, last 3 hours
az monitor metrics list --resource $ID --metric AzureOpenAIRequests \
  --aggregation Total --interval PT5M --offset 3h \
  --filter "ModelDeploymentName eq '*' and StatusCode eq '*'" -o table

# Peak PTU utilisation per deployment, last 24 hours
az monitor metrics list --resource $ID --metric AzureOpenAIProvisionedManagedUtilizationV2 \
  --aggregation Maximum --interval PT1H --offset 24h \
  --filter "ModelDeploymentName eq '*'" -o table

Diagnostic logs and KQL

Resource logs are not collected until you add a diagnostic setting. The categories are Audit, RequestResponse, Trace and AzureOpenAIRequestUsage (check your account's list, as it changes). They land in the AzureDiagnostics table.

WS=$(az monitor log-analytics workspace show -g rg-monitor -n law-prod --query id -o tsv)

az monitor diagnostic-settings create --name aoai-to-law --resource $ID --workspace $WS \
  --logs '[{"category":"Audit","enabled":true},{"category":"RequestResponse","enabled":true}]' \
  --metrics '[{"category":"AllMetrics","enabled":true}]'

Errors by operation and result code:

AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Category == "RequestResponse"
| where TimeGenerated > ago(3h)
| summarize calls = count() by OperationName, ResultSignature, bin(TimeGenerated, 5m)
| order by TimeGenerated desc

Token usage per deployment from exported metrics:

AzureMetrics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where MetricName in ("ProcessedPromptTokens", "GeneratedTokens")
| where TimeGenerated > ago(1d)
| summarize tokens = sum(Total) by MetricName, bin(TimeGenerated, 1h)

Who changed a deployment or key (control plane):

AzureActivity
| where ResourceProviderValue =~ "MICROSOFT.COGNITIVESERVICES"
| where OperationNameValue has_any ("deployments/write", "deployments/delete", "regenerateKey", "accounts/write")
| project TimeGenerated, Caller, OperationNameValue, ActivityStatusValue, _ResourceId
| order by TimeGenerated desc

Prevent it next time

  • Keep a script that runs the deployment and quota queries above weekly and posts the output to your team channel, so you spot retiring versions and quota pressure early.
  • Create the diagnostic setting with Azure Policy so every new account sends Audit and RequestResponse logs to Log Analytics from day one.
  • Add metric alerts on AzureOpenAIRequests filtered to StatusCode 429 and 5xx, and on PTU utilisation above your chosen threshold.
  • Move apps to Entra ID and set disableLocalAuth=true once the logs show no key-based callers remain.
  • Store the curl test call in your runbook so the first responder can separate "Azure OpenAI is down" from "our app is broken" in under a minute.