# Migrating from Azure classic CLI to Azure CLI

If you still use the original Azure classic CLI for your scripts and deployments,
you should consider switching to the new Azure CLI. Azure CLI is designed
for working with the Resource Manager deployment style, while Azure classic CLI
is recommended for only the classic (Azure Service Manager) deployment.

If you are ready to switch, please consider the following before starting:

* Both Azure CLIs can be installed and used side-by-side
* The Azure CLI will not support ASM/Classic mode services
* Scripts are not compatible between both CLIs

## Why switch?

The major reason to switch is that Azure classic CLI is currently only planned
to have support through the end of 2018. The new Azure CLI also offers the following
benefits:

* Clean outputs for common workflows
  * `--out table` for simplified human output
  * `--out json` and `--out jsonc` for JSON outputs
  * `--out tsv` for interacting with tools like grep, AWK, and jq
* Improved and consistent in-tool documentation with `-h`
  * Includes descriptions for groups, commands, and parameters
  * Indicates where to look up required values
  * Examples and links to web content
* Improved command-line productivity
  * Use `[tab][tab]` to lookup parameters, including resource groups and names (only supported in BASH and BASH on Windows)
  * Work with either Azure resource ID values (`--ids`) _or_ resource group and name (`-g -n`)
  * Built in client-side query engine powered by JMESPath

While we believe the above list is compelling, it's important to remember
**the Azure CLI only supports ARM mode**.  If you are managing ASM/Classic 
resources, you must use the Azure classic CLI.

## Getting both CLIs set up side-by-side

First, run `azure --version` and ensure you are using `0.10.5` or later, as
this is required for sharing your credentials between both CLIs.  If you installed
using NPM, upgrade with `npm upgrade -g azure-cli`.  If you used an installer,
we recommend downloading the latest installer to upgrade.

To install the latest Azure CLI, follow the steps for your preferred platform or
environment in our [Installation Guide](https://docs.microsoft.com/cli/azure/install-azure-cli).

Once installed, you run `az configure` and follow the steps to setup your default output format.  

Then run `az login` to login using device authentication.  Once this step is complete you should be authenticated to use both CLIs.  

## Important new concepts in the Azure CLI

Here is a quick list of some new and changed concepts that can help you understand the new tool.

* Interactive Concepts
  * Use `az configure` to setup your default output format
  * You will find help to be generally more useful, try `az vm create -h` for an example
  * Positional parameters are not supported, use `az vm list -g MyGroup` instead of `azure vm list MyGroup`
* Automation and Scripting Concepts
  * You can refer to resources using their Azure resource ID with `--ids` or with the resource group and name using `-g [rg] -n [name]`
  * Use `--query "[expression]"` to extract single values
  * Use `--out tsv` to get plain (no mark-up) value output
  * Use `@-` to pipe values such as `az vm list --query [0].[id] --out tsv | az vm show --ids @-`
* Service Specific Concepts
  * VM power state is no longer included in `az vm list`, use `az vm get-instance-view` instead

## Moving scripts from Azure classic CLI to Azure CLI 

Generally, converting a script from Azure classic CLI to Azure CLI follows these steps:

1. Switch `azure` commands to `az` commands
2. Update commands to use new input values
3. Update script to use new output formats
4. Use `--query` to extract values reliably

Below, we break down each of these steps.

### Finding and switching to `az` commands

While most commands keep the same group and command names between the Azure classic CLI and the latest Azure CLI, we've built a
[azure to az conversion table](https://github.com/Azure/azure-cli/blob/master/doc/azure2az_commands.rst) for common commands.

#### Set vs. Update

Mutate operations now use the `update` verb instead of `set`.  While the classic CLI
exposed some common operations as parameters, such as:

```
$ azure vm set -g MyGroup -n MyName --nic-ids $MyNicID
$ azure vm set -g MyGroup -n MyName --tags myTagName=MyTagValue
```

The Azure CLI `update` commands work generically against the resource, for example:
```
$ az vm update -g MyGroup -n MyName --add networkProfile.networkInterfaces primary=false id=$MyNicID
$ az vm update -g MyGroup -n MyName --set tags.myTagName=MyTagValue
```

#### Commands with complex input

Some commands which required complex input, such as JSON strings and documents,
have been changed to add/remove single values, instead of requiring users to
pull down the document, modify, and set the new document.  For these commands,
see help (`-h`) for details on the specific command.

An example of this is `azure storage cors set` being replaced by `az storage cors add`.

### Updating input values

Once you have identified the `az` commands required for your script, you immediately
notice changes to how inputs are handled.  The Azure CLI does not accept
'positional parameters' such as `azure vm show MyRG MyName`, but instead requires
parameter flags: `az vm show -g MyRG -n MyName`.  

In addition, when an input value is missing, we will show an error indicating the
missing parameters, instead of prompting the user automatically:

```
$ az vm show
az vm show: error: (--name --resource-group | --ids) are required
```

In addition to using resource groups and names (`-g`, `-n`), you can also refer to
resources directly by ID value using `--ids`:

```
$ MyVar=$(az vm list --query [0].id --out tsv)
$ echo $MyVar
/subscriptions/xxxx/resourceGroups/VMGROUP1/providers/Microsoft.Compute/virtualMachines/VM-Data
$ az vm show --ids $MyVar --out table
ResourceGroup    Name     VmId                                  Location    ProvisioningState
---------------  -------  ------------------------------------  ----------  -------------------
VMGROUP1         VM-Data  63edd6a0-2796-49e6-acc1-ad3f8bd94f13  westus      Succeeded
```

When working with files, you can use the `@` symbol to indicate the contents of a file or file descriptor.

```
$ az role create --role-definition @MyOnCallRoleDef.json
```

> **TIP** Use `@-` as short-hand to pass STDIN as a value. 

### Working with output formats

The Azure CLI supports 4 primary output formats:

1. json  - standard JSON formatted object graphs
2. jsonc - colorized JSON
3. tsv   - provides "UNIX-style" output (fields delimited with tabs, records with newlines)
4. table - simplified human-readable output

You can set your default output format with the `az configure` command or on a
by-command basis using `--out` parameter.  

Tips:
* Use `--out tsv` for raw output that is easy to parse with command-line tools
* Use `--out json` for outputting object graphs (nested objects), both `tsv` and `table` will only show fields from the outer-most object.
* Avoid using `--out jsonc` output programmatically as not all tools will accept the ANSI values that provide color in the Shell
* Currently, `--out table` does not work with some formatted outputs.

```
$ az vm list --query [0].name --out json
"VM-Data"
$ az vm list --query [0].name --out tsv
VM-Data
$ az vm list --query [0].name --out table
Result
--------
VM-Data
```

### Filtering down output values

A common pattern in Azure classic CLI scripts is using command-line tools, such as
AWK, grep, and jq, to extract values from output documents:

```
$ azure vm list --json \
     | jq -r '.[].storageProfile.osDisk.vhd.uri' \
     | cut -d / -f3 \
     | cut -d . -f1 \
     | uniq -c \
     | sort -bgr

$ MY_SUBSCRIPTION_ID=$(azure account show --json | jq -r '.[0].id')
```

With the Azure CLI, you can now use the `--query '[expression]'` parameter and the [JMESPath](http://jmespath.org/)
query language to extract values.

```
$ az vm list --query "[].{name:name,os:storageProfile.osDisk.osType}" --out table
Name           Os
-------------  -------
VM-Data        Windows
VM-StagingWeb  Linux
VM-Web         Linux
MyNewVM        Linux

$ az vm list --query "[].{name:name,os:storageProfile.osDisk.osType}" --out tsv
VM-Data	Windows
VM-StagingWeb	Linux
VM-Web	Linux
MyNewVM	Linux

$ az vm list --query "[].{name:name,os:storageProfile.osDisk.osType}" --out json
[
  {
    "name": "VM-Data",
    "os": "Windows"
  },
  {
    "name": "VM-StagingWeb",
    "os": "Linux"
  },
  {
    "name": "VM-Web",
    "os": "Linux"
  },
  {
    "name": "MyNewVM",
    "os": "Linux"
  }
]
```

You can also extract single values.  Using `--out tsv` will prevent any unintended quotes:

```
az vm list --query "[0].id" --out tsv
/subscriptions/xxxx/resourceGroups/VMGROUP1/providers/Microsoft.Compute/virtualMachines/VM-Web
```
