Attaching Existing OS VHD to New Virtual Machine in Microsoft Azure
Post date: Sep 05, 2017 8:0:28 AM
I had a problem with Microsoft Azure cloud service. The last time I looked, the Azure new Portal, and the old portal, do not have the function to attach an existing OS VHD page blob to a newly created virtual machine. One can easily select an selecting EBS as the OS disk when creating a new Amazon Web Services instance. For some reason, Microsoft product managers decided to make it more difficult for Azure users to do that in Azure.
The only way to do the above is to use the command line tools. Available tools are Azure PowerShell, Azure CLI 2.0, and Azure Xplat-CLI. The three tools each have different syntax, although Azure CLI 2.0 and Azure Xplat-CLI are quite close.
There is a lot of information to go through. This post gives the details of how to attach an existing OS VHD to a new virtual machine in Microsoft Azure, using Azure Xplat-CLI. The details of using Azure PowerShell to do the same thing will be given in a follow-up post.
When reading take note that lines that are too long are warped to the following line in the following copy and paste from the terminal.
Azure Xplat-CLI
Azure Xplat-CLI is a cross platform CLI for Windows, Mac and Linux. It supports both Service Management mode and Resource Manager mode. It is hosted on GitHub. You need to have Node.js installed first.
I use openSUSE 13.2 and installed nodejs 4.6.1 package from the openSUSE repository.
To install Azure Xplat-CLI, I would recommend to use the npm local mode install to the current directory rather than the global mode install in the GitHub page instructions. The local mode installation easily allows multiple versions of Azure Xplat-CLI to be maintained.
I installed Azure Xplat-CLI in "myprog" directory in my home directory:
chingl@trinity:~/myprog> npm install azure-cli
Here you can see the path to the executable file "azure":
chingl@trinity:~/myprog/node_modules/azure-cli/bin> ls -l total 8 -rwxr-xr-x 1 chingl users 678 May 13 2016 azure -rw-r--r-- 1 chingl users 1611 Mar 26 04:09 azure.js drwxr-xr-x 2 chingl users 23 May 13 2016 windows
Add the above path to your shell:
chingl@trinity:~> export PATH=$HOME/myprog/node_modules/azure-cli/bin:$PATH
Test that the installation works by typing "azure help" :
chingl@trinity:~> azure help
info: Executing command help
info: _ _____ _ ___ ___
info: /_\ |_ / | | | _ \ __|
info: _ ___/ _ \__/ /| |_| | / _|___ _ _
info: (___ /_/ \_\/___|\___/|_|_\___| _____)
info: (_______ _ _) _ ______ _)_ _
info: (______________ _ ) (___ _ _)
info:
info: Microsoft Azure: Microsoft's Cloud Platform
info:
info: Tool version 0.10.13
help:
help: Display help for a given command
help: help [options] [command]
You can see that my version of Azure Xplat-CLI is 0.10.13.
Login to Azure with Azure Xplat-CLI
Login to Azure with your user ID:
chingl@trinity:~> azure login --username myusername@mydomain.com
info: Executing command login
Password: ****************
+ Authenticating...
error: Get Token request returned http error: 400 and server response: {"error":"invalid_grant","error_description":"AADSTS70002: Error validating credentials. AADSTS50054: Old password is used for authentication.\r\nTrace ID: 6939b42b-36f1-400e-8634-0affc9ab4200\r\nCorrelation ID: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\r\nTimestamp: 2017-06-21 04:54:11Z","error_codes":[70002,50054],"timestamp":"2017-06-21 04:54:11Z","trace_id":"6939b42b-36f1-400e-8634-0affc9ab4200","correlation_id":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"}
error: Error information has been recorded to /home/chingl/.azure/azure.err
error: login command failed
chingl@trinity:~>
Microsoft Live supports this concept of the same email address belonging to both personal and work accounts, with different passwords. If you encounter the same problem above, the most expedient solution is to login without specifing the Azure user ID:
chingl@trinity:~> azure login
info: Executing command login
- Authenticating...info: To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code H5ZDVVFB7 to authenticate.
\
Follow the instructions to open a web browser with the given URL and input the given code as shown in the screen shot below:
Select the appropriate Azure ID to login in the subsequent pages. Upon successful authentication:
Close the browser window and we are ready to go!
chingl@trinity:~> azure login
info: Executing command login
\info: To sign in, use a web browser to open the page https://aka.ms/devicelogin and enter the code H5ZDVVFB7 to authenticate.
|info: Added subscription Microsoft Partner Network
+
info: login command OK
chingl@trinity:~>
Azure Xplat-CLI Mode
Ensure that we are in Resource Manager mode and change the mode if necessary:
chingl@trinity:~> azure config mode arm
info: Executing command config mode
info: New mode is arm
info: config mode command OK
chingl@trinity:~>
Details of Existing OS VHD
The VHD has SUSE Linux Enterprise 12 SP1 installed from Azure image.
Storage Account: cglssd
Resource group: default-storage-southeastasia
Location: Southeast Asia
Performance: Premium
Replication: Locally-redundant storage (LRS)
Container: vhds
VHD page blob name: triton22016525164553.vhd
URL: https://cglssd.blob.core.windows.net/vhds/triton22016525164553.vhd
Type: Page blob
Size: 30 GiB
This OS VHD is the old unmanaged disk. The new Azure Managed Disks provide new features and should be used for new VHDs. While it is possible to convert unmanaged disk to Managed Disk, I have not done so.
Note that the so called location is actually the Azure region. You need the appropriate "location" for the commands below.
Azure Regions
The available Azure regions:
chingl@trinity:~> azure location list --details
info: Executing command location list
+ Getting ARM registered providers
warn: The "location list" commands is changed to list subscription's locations. For old information, use "provider list or show" commands.
info: Getting locations...
data:
data: Location : eastasia
data: DisplayName : East Asia
data: Latitude : 22.267
data: Longitude : 114.188
data: Providers : Microsoft.Cache, Microsoft.ClassicCompute, Microsoft.ClassicNetwork, Microsoft.ClassicStorage, Microsoft.Compute, Microsoft.HDInsight, microsoft.insights, Microsoft.KeyVault, Microsoft.MobileEngagement, Microsoft.Network, Microsoft.OperationalInsights, Microsoft.ResourceHealth, Microsoft.SiteRecovery, Microsoft.Sql, Microsoft.Storage, Microsoft.Web, Microsoft.ADHybridHealthService, Microsoft.Authorization, Microsoft.Billing, Microsoft.Commerce, Microsoft.Features, Microsoft.Resources, microsoft.support
data:
data: Location : southeastasia
data: DisplayName : Southeast Asia
data: Latitude : 1.283
data: Longitude : 103.833
data: Providers : Microsoft.Cache, Microsoft.ClassicCompute, Microsoft.ClassicNetwork, Microsoft.ClassicStorage, Microsoft.Compute, Microsoft.HDInsight, microsoft.insights, Microsoft.KeyVault, Microsoft.MobileEngagement, Microsoft.Network, Microsoft.OperationalInsights, Microsoft.ResourceHealth, Microsoft.SiteRecovery, Microsoft.Sql, Microsoft.Storage, Microsoft.Web, Microsoft.ADHybridHealthService, Microsoft.Authorization, Microsoft.Billing, Microsoft.Commerce, Microsoft.Features, Microsoft.Resources, microsoft.support
data:
Virtual Network
Create a new virtual network and subnet if there is no existing one:
chingl@trinity:~> azure network vnet create --resource-group default-storage-southeastasia --name vnet1 --location southeastasia --address-prefixes 10.0.0.0/16
info: Executing command network vnet create
+ Looking up the virtual network "vnet1"
+ Creating virtual network "vnet1"
data: Name : vnet1
data: Type : Microsoft.Network/virtualNetworks
data: Location : southeastasia
data: Address Space:
data: Address Prefixes:
data: 10.0.0.0/16
data: Subnets : []
data: Virtual Network Peerings : []
data: Resource Guid : 09a14e69-4d9c-44fe-b462-cf54632e60e2
data: Provisioning State : Succeeded
data: Etag : W/"74a460f3-2880-44b2-96cb-f311c29efbf4"
info: network vnet create command OK
chingl@trinity:~>
chingl@trinity:~> azure network vnet subnet create --resource-group default-storage-southeastasia --vnet-name vnet1 --name vnet1-subnet1 --address-prefix 10.0.1.0/24
info: Executing command network vnet subnet create
+ Looking up the subnet "vnet1-subnet1"
+ Creating subnet "vnet1-subnet1"
data: Address Prefix : 10.0.1.0/24
data: Provisioning State : Succeeded
data: Name : vnet1-subnet1
data: Etag : W/"042a5c66-213a-4414-90fe-fa5a29e6e907"
info: network vnet subnet create command OK
chingl@trinity:~>
Note that for the two commands above, it may be necessary to add the option "--subscription" with the subscription identifier if one has multiple active subscriptions.
Network Interface Without Public IP Address
Create a new network interface (without public IP address) if there is no existing one, with a specified private IP address:
chingl@trinity:~> azure network nic create --resource-group default-storage-southeastasia --name nic1 --location southeastasia --private-ip-address 10.0.1.2 --private-ip-version IPv4 --subnet-name vnet1-subnet1 --subnet-vnet-name vnet1
info: Executing command network nic create
+ Looking up the network interface "nic1"
+ Creating network interface "nic1"
error: Private static IP address 10.0.1.2 falls within reserved IP range of subnet prefix 10.0.1.0/24.
error: Error information has been recorded to /home/chingl/.azure/azure.err
error: network nic create command failed
chingl@trinity:~>
chingl@trinity:~> azure network nic create --resource-group default-storage-southeastasia --name nic1 --location southeastasia --private-ip-address 10.0.1.3 --private-ip-version IPv4 --subnet-name vnet1-subnet1 --subnet-vnet-name vnet1
info: Executing command network nic create
+ Looking up the network interface "nic1"
+ Creating network interface "nic1"
error: Private static IP address 10.0.1.3 falls within reserved IP range of subnet prefix 10.0.1.0/24.
error: Error information has been recorded to /home/chingl/.azure/azure.err
error: network nic create command failed
chingl@trinity:~>
Creating a network interface with private IP address of 10.0.1.2 failed. Retrying with 10.0.1.3 again failed. I could not find documentation that these are within reserved IP range.
Retry with private IP address of 10.0.1.4 succeeded:
chingl@trinity:~> azure network nic create --resource-group default-storage-southeastasia --name nic1 --location southeastasia --private-ip-address 10.0.1.4 --private-ip-version IPv4 --subnet-name vnet1-subnet1 --subnet-vnet-name vnet1
info: Executing command network nic create
+ Looking up the network interface "nic1"
+ Creating network interface "nic1"
data: Name : nic1
data: Type : Microsoft.Network/networkInterfaces
data: Location : southeastasia
data: Ip Configurations:
data: Private IP Address : 10.0.1.4
data: Private IP Allocation Method : Static
data: Private IP Address Version : IPv4
data: Subnet:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/vnet1-subnet1
data: Primary : true
data: Provisioning State : Succeeded
data: Name : default-ip-config
data: Etag : W/"d7cda717-5ee3-483a-8b1d-168c3c6d7e91"
data:
data: Dns Settings:
data: Dns Servers : []
data: Applied Dns Servers : []
data: Internal Domain Name Suffix : nfhkccm2jx5ejndcz3kgglta2c.ix.internal.cloudapp.net
data: Enable Accelerated Networking : false
data: Enable IP Forwarding : false
data: Resource Guid : 6c462e86-1a4c-411e-96cc-f30e8847e230
data: Provisioning State : Succeeded
data: Etag : W/"d7cda717-5ee3-483a-8b1d-168c3c6d7e91"
info: network nic create command OK
chingl@trinity:~>
Network Interface With Public IP Address
To create a new network interface, with public IP address, if there is no existing one, with a specified private IP address, first create a public IP address that is static, otherwise the IP address will change every time the virtual machine is shut down and then started, with a domain name prefix of "triton-reborn":
chingl@trinity:~> azure network public-ip create --resource-group default-storage-southeastasia --name triton-reborn-pubip1 --location southeastasia --allocation-method Static --ip-version IPv4 --domain-name-label triton-reborn
info: Executing command network public-ip create
+ Looking up the public ip address "triton-reborn-pubip1"
+ Creating public ip address "triton-reborn-pubip1"
data: Name : triton-reborn-pubip1
data: Type : Microsoft.Network/publicIPAddresses
data: Location : southeastasia
data: Public IP Allocation Method : Static
data: Public IP Address Version : IPv4
data: Dns Settings:
data: Domain Name Label : triton-reborn
data: Fqdn : triton-reborn.southeastasia.cloudapp.azure.com
data: Ip Address : 52.187.114.34
data: Idle Timeout In Minutes : 4
data: Resource Guid : fa85dd26-02ad-4660-a25c-88e9f4ea75d8
data: Provisioning State : Succeeded
data: Etag : W/"1285dc26-4350-4aec-928b-e2f0c6cc4e55"
info: network public-ip create command OK
chingl@trinity:~>
Create the network interface with the public IP address attached:
chingl@trinity:~> azure network nic create --resource-group default-storage-southeastasia --name triton-reborn-nic1 --location southeastasia --private-ip-address 10.0.1.5 --private-ip-version IPv4 --subnet-name vnet1-subnet1 --subnet-vnet-name vnet1 --public-ip-name triton-reborn-pubip1
info: Executing command network nic create
+ Looking up the network interface "triton-reborn-nic1"
+ Creating network interface "triton-reborn-nic1"
data: Name : triton-reborn-nic1
data: Type : Microsoft.Network/networkInterfaces
data: Location : southeastasia
data: Ip Configurations:
data: Private IP Address : 10.0.1.5
data: Private IP Allocation Method : Static
data: Private IP Address Version : IPv4
data: Subnet:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/vnet1-subnet1
data: Primary : true
data: Public IP Address:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/publicIPAddresses/triton-reborn-pubip1
data: Provisioning State : Succeeded
data: Name : default-ip-config
data: Etag : W/"1d582416-3bbe-4972-bece-4ef6a5d60327"
data:
data: Dns Settings:
data: Dns Servers : []
data: Applied Dns Servers : []
data: Internal Domain Name Suffix : nfhkccm2jx5ejndcz3kgglta2c.ix.internal.cloudapp.net
data: Enable Accelerated Networking : false
data: Enable IP Forwarding : false
data: Resource Guid : 9334cd2f-1b92-4604-8252-f0bfe2ea2bb8
data: Provisioning State : Succeeded
data: Etag : W/"1d582416-3bbe-4972-bece-4ef6a5d60327"
info: network nic create command OK
chingl@trinity:~>
Virtual Machine Sizes
You can see the list of available virtual machine sizes for a particular region:
chingl@trinity:~> azure vm sizes --location southeastasia
info: Executing command vm sizes
+ Listing virtual machine sizes available in the location "southeastasia"
data: Name CPU Cores Memory (MB) Max data-disks Max data-disk Size (MB) Max OS-disk Size (MB)
data: ---------------------- --------- ----------- -------------- ----------------------- ---------------------
data: Standard_NV6 6 57344 24 389120 1047552
data: Standard_NV12 12 114688 48 696320 1047552
data: Standard_NV24 24 229376 64 1474560 1047552
data: Standard_A0 1 768 1 20480 1047552
Make sure to select a virtual machine size that is compatible with the storage account type.
Create Virtual Machine
Create a new virtual machine, attaching the existing VHD and the newly created network interface:
chingl@trinity:~> azure vm create --resource-group default-storage-southeastasia --name triton-reborn --nic-name triton-reborn-nic1 --location southeastasia --os-type Linux --vm-size Standard_DS2_v2 --storage-account-name cglssd --storage-account-container-name vhds --os-disk-vhd https://cglssd.blob.core.windows.net/vhds/triton22016525164553.vhd
info: Executing command vm create
+ Looking up the VM "triton-reborn"
info: Using the VM Size "Standard_DS2_v2"
+ Looking up the NIC "triton-reborn-nic1"
info: Found an existing NIC "triton-reborn-nic1"
info: Found an IP configuration with virtual network subnet id "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/vnet1-subnet1" in the NIC "triton-reborn-nic1"
info: This NIC IP configuration has a public ip already configured "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourcegroups/default-storage-southeastasia/providers/microsoft.network/publicipaddresses/triton-reborn-pubip1", any public ip parameters if provided, will be ignored.
+ Looking up the storage account cglssd
+ Looking up the storage account clisto3821758791tritonre
info: The storage URI 'https://clisto3821758791tritonre.blob.core.windows.net/' will be used for boot diagnostics settings, and it can be overwritten by the parameter input of '--boot-diagnostics-storage-uri'.
+ Creating VM "triton-reborn"
info: vm create command OK
chingl@trinity:~>
The virtual machine creation has succeeded. The virtual machine has been reborn.
Virtual Machine Detail Listing
Look at the details of the virtual machine:
chingl@trinity:~> azure vm list
info: Executing command vm list
+ Getting virtual machines
data: ResourceGroupName Name ProvisioningState PowerState Location Size
data: ----------------------------- ------------- ----------------- ---------- ------------- ---------------
data: DEFAULT-STORAGE-SOUTHEASTASIA triton-reborn Succeeded VM running southeastasia Standard_DS2_v2
info: vm list command OK
chingl@trinity:~>
chingl@trinity:~> azure vm get-instance-view --resource-group default-storage-southeastasia --name triton-reborn
info: Executing command vm get-instance-view
+ Getting instance view of virtual machine "triton-reborn"
data: id "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Compute/virtualMachines/triton-reborn"
data: name "triton-reborn"
data: type "Microsoft.Compute/virtualMachines"
data: location "southeastasia"
data: hardwareProfile vmSize "Standard_DS2_v2"
data: storageProfile osDisk osType "Linux"
data: storageProfile osDisk name "cli2e46377e33037ec7-os-1504507613294"
data: storageProfile osDisk vhd uri "https://cglssd.blob.core.windows.net/vhds/triton22016525164553.vhd"
data: storageProfile osDisk caching "ReadWrite"
data: storageProfile osDisk createOption "Attach"
data: networkProfile networkInterfaces 0 id "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/networkInterfaces/triton-reborn-nic1"
data: diagnosticsProfile bootDiagnostics enabled true
data: diagnosticsProfile bootDiagnostics storageUri "https://clisto3821758791tritonre.blob.core.windows.net/"
data: provisioningState "Succeeded"
data: instanceView vmAgent vmAgentVersion "WALinuxAgent-2.0.17"
data: instanceView vmAgent statuses 0 code "ProvisioningState/succeeded"
data: instanceView vmAgent statuses 0 level "Info"
data: instanceView vmAgent statuses 0 displayStatus "Ready"
data: instanceView vmAgent statuses 0 message "GuestAgent is running and accepting new configurations."
data: instanceView vmAgent statuses 0 time 2017-09-04T06:54:12.000Z
data: instanceView disks 0 name "cli2e46377e33037ec7-os-1504507613294"
data: instanceView disks 0 statuses 0 code "ProvisioningState/succeeded"
data: instanceView disks 0 statuses 0 level "Info"
data: instanceView disks 0 statuses 0 displayStatus "Provisioning succeeded"
data: instanceView disks 0 statuses 0 time 2017-09-04T06:47:27.289Z
data: instanceView bootDiagnostics consoleScreenshotBlobUri "https://clisto3821758791tritonre.blob.core.windows.net/bootdiagnostics-tritonreb-0a43a370-d650-4a93-8057-f570a07a1510/triton-reborn.0a43a370-d650-4a93-8057-f570a07a1510.screenshot.bmp"
data: instanceView bootDiagnostics serialConsoleLogBlobUri "https://clisto3821758791tritonre.blob.core.windows.net/bootdiagnostics-tritonreb-0a43a370-d650-4a93-8057-f570a07a1510/triton-reborn.0a43a370-d650-4a93-8057-f570a07a1510.serialconsole.log"
data: instanceView statuses 0 code "ProvisioningState/succeeded"
data: instanceView statuses 0 level "Info"
data: instanceView statuses 0 displayStatus "Provisioning succeeded"
data: instanceView statuses 0 time 2017-09-04T06:48:01.603Z
data: instanceView statuses 1 code "PowerState/running"
data: instanceView statuses 1 level "Info"
data: instanceView statuses 1 displayStatus "VM running"
data: vmId "0a43a370-d650-4a93-8057-f570a07a1510"
info: vm get-instance-view command OK
chingl@trinity:~>
The original virtual machine was created from Azure SUSE Linux Enterprise 12 SP1 image. You can see from above that the Azure agent successfully started in the virtual machine.
I SSHed into the virtual machine, ran yast and successfully updated SUSE. The kernel was updated from "Linux triton2 3.12.57-60.35-default #1 SMP Tue Mar 22 10:47:09 UTC 2016 (1cd55eb) x86_64 x86_64 x86_64 GNU/Linux" to "Linux triton2 3.12.74-60.64.40-default #1 SMP Wed May 10 05:07:16 UTC 2017 (4eb35ec) x86_64 x86_64 x86_64 GNU/Linux".
Binding Network Security Group to the Network Interface
One can bind an existing network security group to the network interface when the network interface is created, or later. Here I have an existing network security group named "triton2" that allows inbound connection only from my client IP address, that I bind to the network interface of the virtual machine:
chingl@trinity:~> azure network nic set --resource-group default-storage-southeastasia --name triton-reborn-nic1 --network-security-group-name triton2
info: Executing command network nic set
+ Looking up the network interface "triton-reborn-nic1"
+ Updating network interface "triton-reborn-nic1"
data: Name : triton-reborn-nic1
data: Type : Microsoft.Network/networkInterfaces
data: Location : southeastasia
data: Virtual Machine:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Compute/virtualMachines/triton-reborn
data: Network Security Group:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/Default-Storage-SoutheastAsia/providers/Microsoft.Network/networkSecurityGroups/triton2
data: Ip Configurations:
data: Private IP Address : 10.0.1.5
data: Private IP Allocation Method : Static
data: Private IP Address Version : IPv4
data: Subnet:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/virtualNetworks/vnet1/subnets/vnet1-subnet1
data: Primary : true
data: Public IP Address:
data: Id : /subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/default-storage-southeastasia/providers/Microsoft.Network/publicIPAddresses/triton-reborn-pubip1
data: Provisioning State : Succeeded
data: Name : default-ip-config
data: Etag : W/"c6243655-940e-43c7-a906-b18107b613c7"
data:
data: Dns Settings:
data: Dns Servers : []
data: Applied Dns Servers : []
data: Internal Domain Name Suffix : nfhkccm2jx5ejndcz3kgglta2c.ix.internal.cloudapp.net
data: Mac Address : 00-0D-3A-A1-DE-9F
data: Primary : true
data: Enable Accelerated Networking : false
data: Enable IP Forwarding : false
data: Resource Guid : 9334cd2f-1b92-4604-8252-f0bfe2ea2bb8
data: Provisioning State : Succeeded
data: Etag : W/"c6243655-940e-43c7-a906-b18107b613c7"
info: network nic set command OK
chingl@trinity:~>
Conclusions
There are many functions that are not available in the Azure portal. One has to use command line tools. Command line tools are also sometimes more convenient to use than the portal, especially for repetitive tasks and repeatable deployments. Besides command line, the other deployment method is use of Azure Resource Manager templates.
The above serve as a quick introduction to Azure Xplat-CLI. Together with Azure Resource Manager templates, we can do "Infrastructure as Code" for repeatable deployments in different environments.