File and manage Azure support tickets from the terminal via the az CLI support extension. Use when the user wants to open, draft, list, inspect, or follow up on an Azure support case - "file an Azure support ticket", "open a case with Microsoft", "raise a ticket for this Azure issue", "check my Azure support tickets", "reply on that support case".
Scanned 9/6/2026
Install to Claude Code
npx -y skills add tarujg/azure-support-ticket --skill azure-support-ticket --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Azure Support Ticket?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/tarujg-azure-support-ticket)More formats (shields.io, HTML) on the badges page.
---
description: File and manage Azure support tickets from the terminal via the az CLI support extension. Use when the user wants to open, draft, list, inspect, or follow up on an Azure support case - "file an Azure support ticket", "open a case with Microsoft", "raise a ticket for this Azure issue", "check my Azure support tickets", "reply on that support case".
---
You are filing an Azure support ticket via the `az` CLI. Filing a ticket is a one-way door and it
goes to an external vendor, so the job is not "run the command" - it is "assemble a ticket support
can actually act on, then get explicit approval before submitting".
## Hard rules
1. **Never invent a number, timestamp, region, or resource ID.** If a value is not supplied by the
user or read from a real source, leave it as an explicit `[FILL]` slot and ask. A ticket with
fabricated metrics is worse than no ticket - it sends Microsoft chasing the wrong thing.
2. **Never run `tickets create` without showing the assembled command and getting a clear yes.**
Draft, display, confirm, then submit.
3. **Never guess the problem-classification.** Resolve it programmatically - clone it off a prior
ticket (step 3) or look it up via step 4. Azure's GUIDs change; a stale hardcoded one silently
misroutes the ticket.
4. **`az login` is the user's job.** It needs a browser. Ask them to run it, don't try to automate it.
## Preflight
```bash
az extension add --name support # idempotent
az account show # confirms login; errors if not authed
```
If not logged in, stop and ask the user to run `az login` themselves. In Claude Code, tell them to
prefix with `!` so the output lands in the conversation:
```
! az login
```
Then list what the account can see and pin the subscription:
```bash
az account list -o table
az account set -s <SUBSCRIPTION-ID>
```
Run the list even when defaulting - it is the cheapest confirmation that the login landed on the
right tenant and that the target subscription is actually visible. If it is missing from the list,
the login is on the wrong tenant and everything downstream will fail with confusing errors.
## Defaults
Most people file every ticket on the same subscription. Don't stop to ask which one - resolve it in
this order:
1. `$AZURE_SUPPORT_SUBSCRIPTION`, if set
2. the subscription already active in `az account show`
Only ask when `az account list` shows several and the request names a resource that clearly lives
in a different one.
If `$AZURE_SUPPORT_REF_TICKET` is set, it names a prior ticket to clone the classification from -
this skips the step 4 catalog hunt entirely:
```bash
PC=$(az support in-subscription tickets show \
--ticket-name "$AZURE_SUPPORT_REF_TICKET" \
--query problemClassificationId -o tsv)
```
Fall back to step 4 only when the new ticket is for a different Azure service than the reference.
## Step 1 - Establish what kind of ticket
Four kinds, each with different required extras:
| Kind | Extra fields needed |
|---|---|
| Technical | `--technical-resource` (full ARM resource ID) - optional but speeds triage a lot |
| Quota | `--quota-change-version`, `--quota-change-subtype`, `--quota-change-requests` |
| Billing | none beyond the base set |
| Subscription management | none beyond the base set |
For quota tickets, read the current numbers first - `az quota list --scope <scope>` or
`az vm list-usage --location <region> -o table` - so the request states a real baseline instead of a
guess. This skill files the change request; it does not read quotas. Many quotas are self-service
and need no ticket at all, so check that before filing.
## Step 2 - Gather the data
Base required set for every ticket:
```
--ticket-name slug, alphanumeric + dashes, unique in the subscription
--title one line
--description the body (see template below)
--severity minimal | moderate | critical | highestcriticalimpact
--problem-classification full ARM path, see step 4
--advanced-diagnostic-consent Yes | No
--contact-first-name --contact-last-name
--contact-email --contact-method email | phone
--contact-country ISO 3166-1 alpha-3, e.g. USA
--contact-language e.g. en-us
--contact-timezone Microsoft Time Zone Index name, e.g. "Pacific Standard Time"
```
Severity notes: `critical` requires a paid support plan. `highestcriticalimpact` is Premium-only -
do not select it speculatively, the ticket will be rejected or downgraded.
Useful optional flags: `--start-time` (UTC ISO 8601, when the problem began),
`--contact-additional-emails`, `--require-24-by-7-response`, `--no-wait`.
If the user needs `--contact-method phone`, `--contact-phone-number` becomes required.
## Step 3 - Shortcut: clone an existing ticket's classification
If the user points at a prior ticket (often as a portal URL), read it instead of hunting for GUIDs.
A portal URL looks like:
```
https://portal.azure.com/#view/.../id/%2Fsubscriptions%2F<SUB>%2Fproviders%2Fmicrosoft.support%2Fsupporttickets%2F<TICKET-NAME>/...
```
URL-decode it to recover `<SUB>` and `<TICKET-NAME>`, then:
```bash
az support in-subscription tickets show --ticket-name <TICKET-NAME> -o json
```
Reuse `problemClassificationId` and `serviceId` verbatim. This is faster and more accurate than
searching the service catalog.
## Step 4 - Resolve the problem classification
```bash
# 1. find the service
az support services list --query "[].{name:name, display:displayName}" -o table
# 2. list its problem classifications - select id, NOT just name
az support services problem-classifications list \
--service-name <service-guid> \
--query "[].{id:id, display:displayName}" -o table
```
**Gotcha:** `--problem-classification` is not a bare GUID. It is the full ARM path:
```
/providers/Microsoft.Support/services/<service-guid>/problemClassifications/<pc-guid>
```
`-o table` on a plain list truncates to the short name. Always project the `id` field as shown
above, or you will build an invalid command.
## Step 5 - Write the description
Support engineers triage on specifics. A good description answers what, where, when, how much, and
what you already ruled out. Template:
```
<One-paragraph statement of the problem and the production impact.>
Resource / deployment: <name>
Region(s): <regions>
Onset (UTC): <timestamp>
Pattern: sustained | intermittent | load-correlated
Measured impact:
Baseline: <metric> = <value>
Current: <metric> = <value>
Measured at: <client side | service response headers>
Already ruled out:
<e.g. throttling - provisioned capacity is N, observed usage is M, no 429s observed>
<e.g. client-side - confirmed against service-reported latency, not just caller timing>
Sample request IDs (x-ms-request-id): <3-5 IDs from the degraded window>
Ask: <what you want - RCA, mitigation, capacity change, known-issue confirmation>
```
**Gotcha: the description must be ASCII.** The API rejects a body containing non-ASCII characters
with a vague `JsonDeserializationError: Description contains invalid characters` and no offset
pointing at the culprit. This bites model-written bodies constantly, because em-dashes, curly
quotes, and ellipsis characters are exactly what a model produces. Normalize before submitting:
```bash
python3 - <<'PY' > /tmp/ticket-body-ascii.txt
import sys, unicodedata
s = open('/tmp/ticket-body.txt', encoding='utf-8').read()
for bad, good in {'—':'-','–':'-','“':'"','”':'"','‘':"'",'’':"'",
'…':'...','\xa0':' ','€':'EUR ','£':'GBP ','×':'x'}.items():
s = s.replace(bad, good)
out = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').decode()
lost = sorted({c for c in s if not c.isascii() and c not in ('\xa0',)})
if lost:
print('rewrote or dropped: ' + ' '.join(lost), file=sys.stderr)
print(out, end='')
PY
```
Read the stderr line. Anything listed there was rewritten or silently deleted - a dropped currency
symbol turns "EUR 5000 overcharge" into "5000 overcharge", which changes what you are reporting.
Spell such values out in words and re-run rather than shipping the lossy version.
Do **not** reach for `iconv` here. Measured on macOS: `iconv -f utf-8 -t ascii//TRANSLIT` mangles
curly quotes (`curly "quotes"` becomes `curly "quo"es `) and exits non-zero, and `iconv -c` drops
the character entirely so `em-dash` silently becomes `emdash`. Both corrupt a ticket body in ways
support will misread.
For latency or error-rate tickets specifically, Microsoft's first reply is reliably a request for
timestamps, region, and `x-ms-request-id` samples. Collect those up front or expect a wasted round
trip.
Before filing a latency ticket, sanity-check that the slowdown is server-side. Client-side timing
inflated by caller cancellations, retries, or token-limit truncation is a common false positive and
will get the ticket closed as not-reproducible.
## Step 6 - Assemble, confirm, submit
Show the user the complete command. Get an explicit yes. Then run it.
```bash
az support in-subscription tickets create \
--ticket-name "<slug>" \
--title "<title>" \
--description "<description>" \
--severity moderate \
--problem-classification "/providers/Microsoft.Support/services/<svc>/problemClassifications/<pc>" \
--advanced-diagnostic-consent Yes \
--contact-first-name <First> --contact-last-name <Last> \
--contact-email <email> --contact-method email \
--contact-country USA --contact-language en-us \
--contact-timezone "Pacific Standard Time"
```
Long descriptions are awkward to quote inline. Write the body to a file and interpolate:
```bash
DESC="$(cat /tmp/ticket-body-ascii.txt)" # the normalized file from step 5
az support in-subscription tickets create --description "$DESC" ...
```
On success, report the returned ticket name and the portal URL so the user can track it.
## Follow-up commands
```bash
# list recent tickets (defaults to last week)
az support in-subscription tickets list -o table
# read one
az support in-subscription tickets show --ticket-name <name> -o json
# change severity / status / contact info (severity is locked while an engineer is assigned)
az support in-subscription tickets update --ticket-name <name> --severity critical
# reply on the case
az support in-subscription communication create \
--ticket-name <name> --communication-name <slug> \
--communication-subject "<subject>" --communication-body "<message>"
# read the thread
az support in-subscription communication list --ticket-name <name> -o table
```
**Gotcha:** on `communication create` the subject and body flags are prefixed -
`--communication-subject` and `--communication-body`, not `--subject`/`--body` - while
`--ticket-name` on the same command is not prefixed. Getting this wrong fails with a required-
argument error. `--communication-sender` also exists and is required in some cases.
Attachments go through a file workspace (`az support in-subscription file-workspace` and
`az support in-subscription file`). Check `--help` on those groups for the current flag set rather
than assuming.
## Notes
- Ticket data is only retrievable for 18 months after creation.
- `az support no-subscription` exists for tenant-level issues with no subscription context.
- `--no-wait` returns immediately instead of polling the long-running create operation.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!