Recursively traversing Azure CLI help screens

Recursively traversing Azure CLI help screens

For a simple command line tool, a single help screen (usually invoked with a -h) can show you all of the available functionality. But large complex command line tools may have many subcommands, or even subcommands of subcommands, each with its own help text.

The Azure CLI is such a beast. It has a deeply nested hierarchy of subgroups, and with a single help command you can only see the options in a single group. For example, the command az -h displays this help text:

For version info, use 'az --version'
 
Group
    az
 
Subgroups:
    account   : Manage subscriptions.
    acs       : Manage Azure Container Services.
    ad        : Synchronize on-premises directories and manage Azure Active Directory resources.
    appservice: Manage your Azure Web apps and App Service plans.
    batch     : Manage Azure Batch.
    cloud     : Manage the registered Azure clouds.
    component : Manage and update Azure CLI 2.0 (Preview) components.
    container : Set up automated builds and deployments for multi-container Docker applications.
    disk      : Manage Azure Managed Disks.
    documentdb: Manage your Azure DocumentDB (NoSQL) database accounts.
    feature   : Manage resource provider features, such as previews.
    group     : Manage resource groups.
    image     : Manage custom Virtual Machine Images.
    iot       : Connect, monitor, and control millions of IoT assets.
    keyvault  : Safeguard and maintain control of keys, secrets, and certificates.
    lock      : Manage Azure locks.
    network   : Manages Azure Network resources.
    policy    : Manage resource policies.
    provider  : Manage resource providers.
    redis     : Access to a secure, dedicated cache for your Azure applications.
    resource  : Manage Azure resources.
    role      : Use role assignments to manage access to your Azure resources.
    snapshot  : Manage point-in-time copies of managed disks, native blobs, or other snapshots.
    sql       : Manage Azure SQL databases.
    storage   : Durable, highly available, and massively scalable cloud storage.
    tag       : Manage resource tags.
    vm        : Provision Linux or Windows virtual machines in seconds.
    vmss      : Create highly available, auto-scalable Linux or Windows virtual machines.
 
Commands:
    configure : Configure Azure CLI 2.0 Preview or view your configuration. The command is
                interactive, so just type `az configure` and respond to the prompts.
    feedback  : Loving or hating the CLI?  Let us know!
    login     : Log in to access Azure subscriptions.
    logout    : Log out to remove access to Azure subscriptions.

And the command az storage directory -h displays this help text:

Group
    az storage directory: Manage file storage directories.
 
Subgroups:
    metadata: Manage file storage directory metadata.
 
Commands:
    create  : Creates a new directory under the specified share or parent directory.
    delete  : Deletes the specified empty directory.
    exists  : Indicates whether the directory exists.
    list    : List directories in the specified share.
    show    : Returns all user-defined metadata and system properties for the specified directory.

If you want to see all of the functionality in the Azure CLI, you need to execute every possible help command in a deeply nested tree of commands, as defined in the “Subgroups” sections of the help text for each command/node. Sounds like a task that should be automated!

The Python standard library has a subprocess module with a getoutput function that’s just what we need for grabbing the output of a help command. It works like this:

import subprocess
dir_output = subprocess.getoutput('dir')
print(dir_output) # captured output of running 'dir' command in a subprocess

By combining that trick with a bit of parsing to get the list of subgroups out of the captured output, and rolling those into a function that calls itself recursively for each subgroup within the current help text, we end up with this program to generate a complete list of the help commands for the Azure CLI:

"""Capture azure-cli help output and recursively crawl all help commands for
subgroups. Help commands are printed to console.
"""
import subprocess
import sys
 
def getcommands(helpcmd):
    """Recursively crawl all subgroups, starting from specified help command.
    Passed command assumed to end with -h. For example, 'az vm -h'
    """
    indentation = 4 * (len(helpcmd.split(' ')) - 3)
    print(indentation*' ' + helpcmd)
 
    stdoutdata = subprocess.getoutput(helpcmd) # capture help command output
    subgroups = False # flag to track whether inside the subgroup section
    for line in stdoutdata.split('\n'):
 
        if line.strip() == 'Subgroups:':
            subgroups = True # found start of subgroup section
            continue # skip the 'Subgroups:' line
        if not subgroups:
            continue # skip all lines before subgroup section
        if subgroups and (not line.strip() or line.lstrip() == line):
            break # blank or non-indented line is end of subgroup section
 
        subhelp = subcommand(helpcmd, line) # create help command for subgroup
        getcommands(subhelp) # enumerate help commands for this subgroup
 
def subcommand(helpcmd, line):
    """Return a help command for a subgroup.
 
    helpcmd = an Azure CLI help command (e.g., 'az vm -h')
    line = line of text beginning with a subgroup
        (e.g., 'create        : Create an Azure Virtual Machine.')
 
    Returns the command for getting help on this subgroup
    (e.g., 'az vm create -h')
    """
    # sometimes need to remove trailing ':'
    subgroup = line.strip().split(' ')[0].rstrip(':')
 
    # create list of arguments before the -h
    rootcommand = helpcmd.split(' ')[:-1]
 
    # add this subgroup and -h
    rootcommand.extend([subgroup, '-h'])
 
    return ' '.join(rootcommand) # re-assemble into a help command string
 
if __name__ == '__main__':
    if len(sys.argv) == 2:
        # a help command was passed on command line, so use that
        getcommands(sys.argv[1])
    else:
        # default: start at top-level help command for Azure CLI
        getcommands('az -h')

A few things to note in the code above:

  • The getcommands() function (lines 10-30) takes an Azure CLI help command as an argument. It prints the command to the console, then executes the command and captures its output. And then it calls itself for each entry in its Subgroups section (if any).
  • The task of constructing the help command for a Subgroup entry is handled by the subcommand() function (lines 33-52), which takes a help command and a line from the Subgroups section as arguments, and returns a well-formed Azure CLI help command that can be passed to getcommands().
  • By default, the crawling starts from the root help command az -h, but you can also pass a different starting position on the command line. Here’s an example of how to display the storage directory node of help commands:
python azhelp.py "az storage directory -h"
    az storage directory -h
        az storage directory metadata -h

You can get the code on GitHub, and here’s the full tree of help commands generated from version 2.0.0 of the Azure CLI:

az -h
az account -h
az acs -h
    az acs dcos -h
    az acs kubernetes -h
az ad -h
    az ad app -h
    az ad group -h
    az ad sp -h
    az ad user -h
az appservice -h
    az appservice plan -h
    az appservice web -h
        az appservice web config -h
            az appservice web config appsettings -h
            az appservice web config backup -h
            az appservice web config container -h
            az appservice web config hostname -h
            az appservice web config ssl -h
        az appservice web deployment -h
            az appservice web deployment slot -h
            az appservice web deployment user -h
        az appservice web log -h
        az appservice web source-control -h
az batch -h
    az batch account -h
        az batch account autostorage-keys -h
        az batch account account. -h
        az batch account keys -h
    az batch application -h
        az batch application package -h
        az batch application summary -h
    az batch certificate -h
    az batch job -h
        az batch job all-statistics -h
        az batch job prep-release-status -h
    az batch job-schedule -h
    az batch location -h
        az batch location quotas -h
    az batch node -h
        az batch node file -h
        az batch node remote-desktop -h
        az batch node remote-login-settings -h
        az batch node scheduling -h
        az batch node user -h
    az batch pool -h
        az batch pool all-statistics -h
        az batch pool autoscale -h
        az batch pool node-agent-skus -h
        az batch pool os -h
        az batch pool usage-metrics -h
    az batch task -h
        az batch task file -h
        az batch task subtask -h
az cloud -h
az component -h
az container -h
    az container build -h
    az container release -h
az disk -h
az documentdb -h
az feature -h
az group -h
    az group deployment -h
        az group deployment operation -h
az image -h
az iot -h
    az iot device -h
        az iot device message -h
    az iot hub -h
        az iot hub consumer-group -h
        az iot hub job -h
        az iot hub policy -h
az keyvault -h
    az keyvault certificate -h
        az keyvault certificate contact -h
        az keyvault certificate issuer -h
            az keyvault certificate issuer admin -h
        az keyvault certificate pending -h
    az keyvault key -h
    az keyvault secret -h
az lock -h
az network -h
    az network application-gateway -h
        az network application-gateway address-pool -h
        az network application-gateway auth-cert -h
        az network application-gateway frontend-ip -h
        az network application-gateway frontend-port -h
        az network application-gateway http-listener -h
        az network application-gateway http-settings -h
        az network application-gateway probe -h
        az network application-gateway by -h
        az network application-gateway rule -h
        az network application-gateway ssl-cert -h
        az network application-gateway ssl-policy -h
        az network application-gateway url-path-map -h
            az network application-gateway url-path-map rule -h
        az network application-gateway waf-config -h
    az network dns -h
        az network dns record-set -h
            az network dns record-set a -h
            az network dns record-set aaaa -h
            az network dns record-set cname -h
            az network dns record-set mx -h
            az network dns record-set ns -h
            az network dns record-set ptr -h
            az network dns record-set soa -h
            az network dns record-set srv -h
            az network dns record-set txt -h
        az network dns zone -h
    az network express-route -h
        az network express-route auth -h
        az network express-route peering -h
    az network lb -h
        az network lb address-pool -h
        az network lb frontend-ip -h
        az network lb inbound-nat-pool -h
        az network lb inbound-nat-rule -h
        az network lb probe -h
        az network lb rule -h
    az network your -h
    az network local-gateway -h
    az network nic -h
        az network nic ip-config -h
            az network nic ip-config address-pool -h
            az network nic ip-config inbound-nat-rule -h
    az network nsg -h
        az network nsg rule -h
    az network public-ip -h
    az network route-table -h
        az network route-table route -h
    az network traffic-manager -h
        az network traffic-manager endpoint -h
        az network traffic-manager profile -h
    az network vnet -h
        az network vnet peering -h
        az network vnet subnet -h
    az network vnet-gateway -h
        az network vnet-gateway revoked-cert -h
        az network vnet-gateway root-cert -h
    az network connectivity. -h
    az network vpn-connection -h
        az network vpn-connection shared-key -h
az policy -h
    az policy assignment -h
    az policy definition -h
az provider -h
az redis -h
    az redis patch-schedule -h
az resource -h
    az resource link -h
az role -h
    az role assignment -h
    az role definition -h
az snapshot -h
az sql -h
    az sql db -h
        az sql db data-warehouse -h
        az sql db replication-link -h
        az sql db restore-point -h
        az sql db service-tier-advisor -h
        az sql db transparent-data-encryption -h
    az sql elastic-pools -h
        az sql elastic-pools db -h
        az sql elastic-pools recommended -h
            az sql elastic-pools recommended db -h
    az sql server -h
        az sql server firewall -h
        az sql server service-objective -h
az storage -h
    az storage account -h
        az storage account keys -h
    az storage blob -h
        az storage blob copy -h
        az storage blob lease -h
        az storage blob metadata -h
        az storage blob service-properties -h
    az storage container -h
        az storage container lease -h
        az storage container metadata -h
        az storage container policy -h
    az storage cors -h
    az storage directory -h
        az storage directory metadata -h
    az storage entity -h
    az storage file -h
        az storage file copy -h
        az storage file metadata -h
    az storage logging -h
    az storage message -h
    az storage metrics -h
    az storage queue -h
        az storage queue metadata -h
        az storage queue policy -h
    az storage share -h
        az storage share metadata -h
        az storage share policy -h
    az storage table -h
        az storage table policy -h
az tag -h
az vm -h
    az vm availability-set -h
    az vm requirements. -h
    az vm boot-diagnostics -h
    az vm diagnostics -h
    az vm disk -h
    az vm encryption -h
    az vm extension -h
        az vm extension image -h
    az vm image -h
    az vm nic -h
    az vm unmanaged-disk -h
    az vm user -h
az vmss -h
    az vmss diagnostics -h
    az vmss extension. -h
    az vmss disk -h
    az vmss extension -h
        az vmss extension image -h
    az vmss nic -h