Create a VM from a managed image in Azure

Multiple Virtual Machine can be created from managed images in Azure by using a portal, Azure Command Line Interface (CLI), Azure Cloud shell or Azure Resource Manager Templates. Before Creating a new VM the Managed Image Should be created and the read access to that source VM should be granted to the users who going to use that Managed Image.

  1. Managed Image Creation

Consider You are having one Virtual Machine which runs using a managed disk and that disk contains the required changes. To Create a Managed Image using that managed disk VM, Execute the following script as follows,

i) Open Azure Cloud Shell and switch to your cloud drive file share by using the following command

cd $HOME\clouddrive

ii). Create a PowerShell script in that directory by using nano, vi or any text editor and add the following Source Code. Ex. azure_image_creation.ps1

GitHub :
https://github.com/Eranachandran/Azure_VM_From_Custom_Image/blob/master/azure_image_creation.ps1

################################################################################################################################################
# Script Name: azure_image_creation.ps1
# Author: Eranachandran
# Date : 05-01-2020
# Description: The following powershell script will create a custom azure image from a managed disk
# script usage: ./azure_image_creation.ps1 -resourceGroupName <resourceGroupName> -location <location> -vmName <vmName> -snapshotName <snapshotName> -imageName <imageName>
################################################################################################################################################
##############Required Inputs for this Script starts #################

param(
   [string] $resourceGroupName,
   [string] $location,
   [string] $vmName,
   [string] $snapshotName,
   [string] $imageName
)

##############Required Inputs for this Script starts #################

#Get the VM
$vm = get-azvm -ResourceGroupName $resourceGroupName -Name $vmName

#Create the snapshot configuration
$snapshot =  New-AzSnapshotConfig -SourceUri $vm.StorageProfile.OsDisk.ManagedDisk.Id -Location $location -CreateOption copy

#Take the snapshot
New-AzSnapshot -Snapshot $snapshot -SnapshotName $snapshotName -ResourceGroupName $resourceGroupName

############ Snapshot Creation ends ######################

############### Managed Image Creation Starts #######################

#Get the snapshot
$snapshot = Get-AzSnapshot -ResourceGroupName $resourceGroupName -SnapshotName $snapshotName

#Create the image configuration
$imageConfig = New-AzImageConfig -Location $location
$imageConfig = Set-AzImageOsDisk -Image $imageConfig -OsState Generalized -OsType linux -SnapshotId $snapshot.Id

#Create the image
New-AzImage -ImageName $imageName -ResourceGroupName $resourceGroupName -Image $imageConfig
############### Managed Image Creation Starts #######################

iii). Execute the PowerShell script by using the following command,

./azure_image_creation.ps1 -resourceGroupName ‘Eranachandran_VMSS’ -location ‘East US’ -vmName ‘reddis’ -snapshotName ‘redis-snap’ -imageName ‘redis-custom-image’

Note:
resourceGroupName is the Name of VM’s Resource Group(Which is need to be created as an image), location is the where the VM is located, vmName is Name of the VM, snapshotName is in which name the snapshot needs to be created, imageName is in which name the custom image needs to be created.

iv). After executing the Script the Managed custom image will be created and a snapshot of that VM also will be created.

2. Creating a Virtual Machine From Custom Image

Create a Virtual Machine From custom Virtual Machine by as follows,

i) Create ARM Template from the following Source Code,

GitHub :
https://github.com/Eranachandran/Azure_VM_From_Custom_Image/blob/master/VM_from_Customized_image.json

{
  "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "image_location": {
      "type": "string"
    },
    "imageName": {
      "type": "string"
    },
    "image_Resourcegroup_name": {
      "type": "string"
    },
    "virtualMachineName": {
      "type": "string",
      "metadata": {
        "description": "Name for the Virtual Machine to be provisioned. Azure resource names cannot contain special characters \"/[]:|<>+=;,?*@& or begin with ' _ or end with '. or - Virtual machine name must be unique in the current resource group."
      },
      "minLength": 1,
      "maxLength": 15
    },
    "virtualMachineSize": {
      "type": "string",
      "metadata": {
        "description": "Size of the virtual machine."
      },
      "allowedValues": [
        "Standard_A0",
        "Standard_A1",
        "Standard_A2",
        "Standard_A3",
        "Standard_A4",
        "Standard_A5",
        "Standard_A6",
        "Standard_A7",
        "Standard_D2_v3",
        "Standard_D4_v3",
        "Standard_D8_v3",
        "Standard_D1_v2",
        "Standard_D2_v2",
        "Standard_D3_v2",
        "Standard_D4_v2",
        "Standard_A1_v2",
        "Standard_A2_v2",
        "Standard_A4_v2",
        "Standard_A8_v2"
      ]
    },
    "adminUsername": {
      "type": "string",
      "metadata": {
        "description": "Username for the Virtual Machine.Username cannot contain special characters \"/[]:|<>+=;,?*@& or end with '.'"
      },
      "minLength": 1,
      "maxLength": 20
    },
    "adminPassword": {
      "type": "secureString",
      "metadata": {
        "description": "Password for the Virtual Machine.Password must have 3 of the following: 1 lower case character, 1 upper case character, 1 number, and 1 special character"
      },
      "minLength": 12,
      "maxLength": 123
    }
  },
  "variables": {
    "publicIpAddressName": "[concat(parameters('virtualMachineName'), '-ip')]",
    "networkInterfaceName": "[concat(parameters('virtualMachineName'), take(uniquestring(parameters('virtualMachineName'), deployment().name), 3))]",
    "virtualNetworkName": "[concat('csvnet', take(uniquestring(parameters('virtualMachineName'), deployment().name), 6))]",
    "addressPrefixes": "10.6.0.0/24",
    "subnet_prefix": "10.6.0.0/24",
    "networkSecurityGroupName": "[concat(parameters('virtualMachineName'), '-nsg')]",
    "subnetName": "default",
    "diagnosticsStorageAccountName": "[concat('storagediag', take(uniquestring(parameters('virtualMachineName'),deployment().name), 6))]",
    "nsgId": "[resourceId(resourceGroup().name, 'Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]",
    "vnetId": "[resourceId(resourceGroup().name,'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]",
    "subnetRef": "[concat(variables('vnetId'), '/subnets/', variables('subnetName'))]"
  },
  "resources": [
    {
      "name": "[variables('networkInterfaceName')]",
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2019-07-01",
      "location": "[parameters('image_location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]",
        "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
        "[concat('Microsoft.Network/publicIpAddresses/', variables('publicIpAddressName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "subnet": {
                "id": "[variables('subnetRef')]"
              },
              "privateIPAllocationMethod": "Dynamic",
              "publicIpAddress": {
                "id": "[resourceId(resourceGroup().name, 'Microsoft.Network/publicIpAddresses', variables('publicIpAddressName'))]"
              }
            }
          }
        ],
        "networkSecurityGroup": {
          "id": "[variables('nsgId')]"
        }
      }
    },
    {
      "name": "[variables('networkSecurityGroupName')]",
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2019-02-01",
      "location": "[parameters('image_location')]",
      "properties": {
        "securityRules": [
          {
            "name": "RDP",
            "properties": {
              "priority": 300,
              "protocol": "TCP",
              "access": "Allow",
              "direction": "Inbound",
              "sourceAddressPrefix": "*",
              "sourcePortRange": "*",
              "destinationAddressPrefix": "*",
              "destinationPortRange": "3389"
            }
          }
        ]
      }
    },
    {
      "name": "[variables('virtualNetworkName')]",
      "type": "Microsoft.Network/virtualNetworks",
      "apiVersion": "2018-08-01",
      "location": "[parameters('image_location')]",
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('addressPrefixes')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('subnetName')]",
            "properties": {
              "addressPrefix": "[variables('subnet_prefix')]"
            }
          }
        ]
      }
    },
    {
      "name": "[variables('publicIpAddressName')]",
      "type": "Microsoft.Network/publicIpAddresses",
      "apiVersion": "2019-02-01",
      "location": "[parameters('image_location')]",
      "properties": {
        "publicIpAllocationMethod": "Static"
      },
      "sku": {
        "name": "Standard"
      }
    },
    {
      "name": "[parameters('virtualMachineName')]",
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2019-07-01",
      "location": "[parameters('image_location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/networkInterfaces/', variables('networkInterfaceName'))]",
        "[concat('Microsoft.Storage/storageAccounts/', variables('diagnosticsStorageAccountName'))]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('virtualMachineSize')]"
        },
        "storageProfile": {
          "osDisk": {
            "createOption": "fromImage",
            "managedDisk": {
              "storageAccountType": "Standard_LRS"
            }
          },
          "imageReference": {
            "id": "[resourceId(parameters('image_Resourcegroup_name'),'Microsoft.Compute/images', parameters('imageName'))]"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
            }
          ]
        },
        "osProfile": {
          "computerName": "[parameters('virtualMachineName')]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]",
          "windowsConfiguration": {
            "enableAutomaticUpdates": true,
            "provisionVmAgent": true
          }
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[concat('https://', variables('diagnosticsStorageAccountName'), '.blob.core.windows.net/')]"
          }
        }
      }
    },
    {
      "name": "[variables('diagnosticsStorageAccountName')]",
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2019-06-01",
      "location": "[parameters('image_location')]",
      "properties": {},
      "kind": "Storage",
      "sku": {
        "name": "Standard_LRS"
      }
    }
  ],
  "outputs": {
    "adminUsername": {
      "type": "string",
      "value": "[parameters('adminUsername')]"
    }
  }
}

ii). Execute the ARM Template with required parameters to create a VM from Customized Image.

Note: This way works for Linux Virtual Machines only. Windows Virtual Machines are should be generalized before creating a snapshot, so this way won’t work for Windows Virtual Machines

Reference: https://docs.microsoft.com/en-us