Create and manage Windows VMs in Azure using Python

An Azure Virtual Machine (VM) needs several supporting Azure resources. This article covers creating, managing, and deleting VM resources using Python. You learn how to:

  • Create a Visual Studio project
  • Install packages
  • Create credentials
  • Create resources
  • Perform management tasks
  • Delete resources
  • Run the application

It takes about 20 minutes to do these steps.

Create a Visual Studio project

  1. If you haven't already, install Visual Studio. Select Python development on the Workloads page, and then click Install. In the summary, you can see that Python 3 64-bit (3.6.0) is automatically selected for you. If you have already installed Visual Studio, you can add the Python workload using the Visual Studio Launcher.
  2. After installing and starting Visual Studio, click File > New > Project.
  3. Click Templates > Python > Python Application, enter myPythonProject for the name of the project, select the location of the project, and then click OK.

Install packages

  1. In Solution Explorer, under myPythonProject, right-click Python Environments, and then select Add virtual environment.
  2. On the Add Virtual Environment screen, accept the default name of env, make sure that Python 3.6 (64-bit) is selected for the base interpreter, and then click Create.
  3. Right-click the env environment that you created, click Install Python Package, enter azure in the search box, and then press Enter.

You should see in the output windows that the azure packages were successfully installed.

Create credentials

Before you start this step, make sure that you have an Active Directory service principal. You should also record the application ID, the authentication key, and the tenant ID that you need in a later step.

  1. Open myPythonProject.py file that was created, and then add this code to enable your application to run:

    if __name__ == "__main__":
    
  2. To import the code that is needed, add these statements to the top of the .py file:

    from azure.common.credentials import ServicePrincipalCredentials
    from azure.mgmt.resource import ResourceManagementClient
    from azure.mgmt.compute import ComputeManagementClient
    from azure.mgmt.network import NetworkManagementClient
    from azure.mgmt.compute.models import DiskCreateOption
    
  3. Next in the .py file, add variables after the import statements to specify common values used in the code:

    SUBSCRIPTION_ID = 'subscription-id'
    GROUP_NAME = 'myResourceGroup'
    LOCATION = 'westus'
    VM_NAME = 'myVM'
    

    Replace subscription-id with your subscription identifier.

  4. To create the Active Directory credentials that you need to make requests, add this function after the variables in the .py file:

    def get_credentials():
        credentials = ServicePrincipalCredentials(
            client_id = 'application-id',
            secret = 'authentication-key',
            tenant = 'tenant-id'
        )
    
        return credentials
    

    Replace application-id, authentication-key, and tenant-id with the values that you previously collected when you created your Azure Active Directory service principal.

  5. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    credentials = get_credentials()
    

Create resources

Initialize management clients

Management clients are needed to create and manage resources using the Python SDK in Azure. To create the management clients, add this code under the if statement at then end of the .py file:

resource_group_client = ResourceManagementClient(
    credentials,
    SUBSCRIPTION_ID
)
network_client = NetworkManagementClient(
    credentials,
    SUBSCRIPTION_ID
)
compute_client = ComputeManagementClient(
    credentials,
    SUBSCRIPTION_ID
)

Create the VM and supporting resources

All resources must be contained in a Resource group.

  1. To create a resource group, add this function after the variables in the .py file:

    def create_resource_group(resource_group_client):
        resource_group_params = { 'location':LOCATION }
        resource_group_result = resource_group_client.resource_groups.create_or_update(
            GROUP_NAME, 
            resource_group_params
        )
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    create_resource_group(resource_group_client)
    input('Resource group created. Press enter to continue...')
    

Availability sets make it easier for you to maintain the virtual machines used by your application.

  1. To create an availability set, add this function after the variables in the .py file:

    def create_availability_set(compute_client):
        avset_params = {
            'location': LOCATION,
            'sku': { 'name': 'Aligned' },
            'platform_fault_domain_count': 3
        }
        availability_set_result = compute_client.availability_sets.create_or_update(
            GROUP_NAME,
            'myAVSet',
            avset_params
        )
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    create_availability_set(compute_client)
    print("------------------------------------------------------")
    input('Availability set created. Press enter to continue...')
    

A Public IP address is needed to communicate with the virtual machine.

  1. To create a public IP address for the virtual machine, add this function after the variables in the .py file:

    def create_public_ip_address(network_client):
        public_ip_addess_params = {
            'location': LOCATION,
            'public_ip_allocation_method': 'Dynamic'
        }
        creation_result = network_client.public_ip_addresses.create_or_update(
            GROUP_NAME,
            'myIPAddress',
            public_ip_addess_params
        )
    
        return creation_result.result()
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    creation_result = create_public_ip_address(network_client)
    print("------------------------------------------------------")
    print(creation_result)
    input('Press enter to continue...')
    

A virtual machine must be in a subnet of a Virtual network.

  1. To create a virtual network, add this function after the variables in the .py file:

    def create_vnet(network_client):
        vnet_params = {
            'location': LOCATION,
            'address_space': {
                'address_prefixes': ['10.0.0.0/16']
            }
        }
        creation_result = network_client.virtual_networks.create_or_update(
            GROUP_NAME,
            'myVNet',
            vnet_params
        )
        return creation_result.result()
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    creation_result = create_vnet(network_client)
    print("------------------------------------------------------")
    print(creation_result)
    input('Press enter to continue...')
    
  3. To add a subnet to the virtual network, add this function after the variables in the .py file:

    def create_subnet(network_client):
        subnet_params = {
            'address_prefix': '10.0.0.0/24'
        }
        creation_result = network_client.subnets.create_or_update(
            GROUP_NAME,
            'myVNet',
            'mySubnet',
            subnet_params
        )
    
        return creation_result.result()
    
  4. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    creation_result = create_subnet(network_client)
    print("------------------------------------------------------")
    print(creation_result)
    input('Press enter to continue...')
    

A virtual machine needs a network interface to communicate on the virtual network.

  1. To create a network interface, add this function after the variables in the .py file:

    def create_nic(network_client):
        subnet_info = network_client.subnets.get(
            GROUP_NAME, 
            'myVNet', 
            'mySubnet'
        )
        publicIPAddress = network_client.public_ip_addresses.get(
            GROUP_NAME,
            'myIPAddress'
        )
        nic_params = {
            'location': LOCATION,
            'ip_configurations': [{
                'name': 'myIPConfig',
                'public_ip_address': publicIPAddress,
                'subnet': {
                    'id': subnet_info.id
                }
            }]
        }
        creation_result = network_client.network_interfaces.create_or_update(
            GROUP_NAME,
            'myNic',
            nic_params
        )
    
        return creation_result.result()
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    creation_result = create_nic(network_client)
    print("------------------------------------------------------")
    print(creation_result)
    input('Press enter to continue...')
    

Now that you created all the supporting resources, you can create a virtual machine.

  1. To create the virtual machine, add this function after the variables in the .py file:

    def create_vm(network_client, compute_client):  
        nic = network_client.network_interfaces.get(
            GROUP_NAME, 
            'myNic'
        )
        avset = compute_client.availability_sets.get(
            GROUP_NAME,
            'myAVSet'
        )
        vm_parameters = {
            'location': LOCATION,
            'os_profile': {
                'computer_name': VM_NAME,
                'admin_username': 'azureuser',
                'admin_password': 'Azure12345678'
            },
            'hardware_profile': {
                'vm_size': 'Standard_DS1'
            },
            'storage_profile': {
                'image_reference': {
                    'publisher': 'MicrosoftWindowsServer',
                    'offer': 'WindowsServer',
                    'sku': '2012-R2-Datacenter',
                    'version': 'latest'
                }
            },
            'network_profile': {
                'network_interfaces': [{
                    'id': nic.id
                }]
            },
            'availability_set': {
                'id': avset.id
            }
        }
        creation_result = compute_client.virtual_machines.create_or_update(
            GROUP_NAME, 
            VM_NAME, 
            vm_parameters
        )
    
        return creation_result.result()
    

    Note

    This tutorial creates a virtual machine running a version of the Windows Server operating system. To learn more about selecting other images, see Navigate and select Azure virtual machine images with Windows PowerShell and the Azure CLI.

  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    creation_result = create_vm(network_client, compute_client)
    print("------------------------------------------------------")
    print(creation_result)
    input('Press enter to continue...')
    

Perform management tasks

During the lifecycle of a virtual machine, you may want to run management tasks such as starting, stopping, or deleting a virtual machine. Additionally, you may want to create code to automate repetitive or complex tasks.

Get information about the VM

  1. To get information about the virtual machine, add this function after the variables in the .py file:

    def get_vm(compute_client):
        vm = compute_client.virtual_machines.get(GROUP_NAME, VM_NAME, expand='instanceView')
        print("hardwareProfile")
        print("   vmSize: ", vm.hardware_profile.vm_size)
        print("\nstorageProfile")
        print("  imageReference")
        print("    publisher: ", vm.storage_profile.image_reference.publisher)
        print("    offer: ", vm.storage_profile.image_reference.offer)
        print("    sku: ", vm.storage_profile.image_reference.sku)
        print("    version: ", vm.storage_profile.image_reference.version)
        print("  osDisk")
        print("    osType: ", vm.storage_profile.os_disk.os_type.value)
        print("    name: ", vm.storage_profile.os_disk.name)
        print("    createOption: ", vm.storage_profile.os_disk.create_option.value)
        print("    caching: ", vm.storage_profile.os_disk.caching.value)
        print("\nosProfile")
        print("  computerName: ", vm.os_profile.computer_name)
        print("  adminUsername: ", vm.os_profile.admin_username)
        print("  provisionVMAgent: {0}".format(vm.os_profile.windows_configuration.provision_vm_agent))
        print("  enableAutomaticUpdates: {0}".format(vm.os_profile.windows_configuration.enable_automatic_updates))
        print("\nnetworkProfile")
        for nic in vm.network_profile.network_interfaces:
            print("  networkInterface id: ", nic.id)
        print("\nvmAgent")
        print("  vmAgentVersion", vm.instance_view.vm_agent.vm_agent_version)
        print("    statuses")
        for stat in vm_result.instance_view.vm_agent.statuses:
            print("    code: ", stat.code)
            print("    displayStatus: ", stat.display_status)
            print("    message: ", stat.message)
            print("    time: ", stat.time)
        print("\ndisks");
        for disk in vm.instance_view.disks:
            print("  name: ", disk.name)
            print("  statuses")
            for stat in disk.statuses:
                print("    code: ", stat.code)
                print("    displayStatus: ", stat.display_status)
                print("    time: ", stat.time)
        print("\nVM general status")
        print("  provisioningStatus: ", vm.provisioning_state)
        print("  id: ", vm.id)
        print("  name: ", vm.name)
        print("  type: ", vm.type)
        print("  location: ", vm.location)
        print("\nVM instance status")
        for stat in vm.instance_view.statuses:
            print("  code: ", stat.code)
            print("  displayStatus: ", stat.display_status)
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    get_vm(compute_client)
    print("------------------------------------------------------")
    input('Press enter to continue...')
    

Stop the VM

You can stop a virtual machine and keep all its settings, but continue to be charged for it, or you can stop a virtual machine and deallocate it. When a virtual machine is deallocated, all resources associated with it are also deallocated and billing ends for it.

  1. To stop the virtual machine without deallocating it, add this function after the variables in the .py file:

    def stop_vm(compute_client):
        compute_client.virtual_machines.power_off(GROUP_NAME, VM_NAME)
    

    If you want to deallocate the virtual machine, change the power_off call to this code:

    compute_client.virtual_machines.deallocate(GROUP_NAME, VM_NAME)
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    stop_vm(compute_client)
    input('Press enter to continue...')
    

Start the VM

  1. To start the virtual machine, add this function after the variables in the .py file:

    def start_vm(compute_client):
        compute_client.virtual_machines.start(GROUP_NAME, VM_NAME)
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    start_vm(compute_client)
    input('Press enter to continue...')
    

Resize the VM

Many aspects of deployment should be considered when deciding on a size for your virtual machine. For more information, see VM sizes.

  1. To change the size of the virtual machine, add this function after the variables in the .py file:

    def update_vm(compute_client):
        vm = compute_client.virtual_machines.get(GROUP_NAME, VM_NAME)
        vm.hardware_profile.vm_size = 'Standard_DS3'
        update_result = compute_client.virtual_machines.create_or_update(
            GROUP_NAME, 
            VM_NAME, 
            vm
        )
    
    return update_result.result()
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    update_result = update_vm(compute_client)
    print("------------------------------------------------------")
    print(update_result)
    input('Press enter to continue...')
    

Add a data disk to the VM

Virtual machines can have one or more data disks that are stored as VHDs.

  1. To add a data disk to the virtual machine, add this function after the variables in the .py file:

    def add_datadisk(compute_client):
        disk_creation = compute_client.disks.create_or_update(
            GROUP_NAME,
            'myDataDisk1',
            {
                'location': LOCATION,
                'disk_size_gb': 1,
                'creation_data': {
                    'create_option': DiskCreateOption.empty
                }
            }
        )
        data_disk = disk_creation.result()
        vm = compute_client.virtual_machines.get(GROUP_NAME, VM_NAME)
        add_result = vm.storage_profile.data_disks.append({
            'lun': 1,
            'name': 'myDataDisk1',
            'create_option': DiskCreateOption.attach,
            'managed_disk': {
                'id': data_disk.id
            }
        })
        add_result = compute_client.virtual_machines.create_or_update(
            GROUP_NAME,
            VM_NAME,
            vm)
    
        return add_result.result()
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    add_result = add_datadisk(compute_client)
    print("------------------------------------------------------")
    print(add_result)
    input('Press enter to continue...')
    

Delete resources

Because you are charged for resources used in Azure, it's always a good practice to delete resources that are no longer needed. If you want to delete the virtual machines and all the supporting resources, all you have to do is delete the resource group.

  1. To delete the resource group and all resources, add this function after the variables in the .py file:

    def delete_resources(resource_group_client):
        resource_group_client.resource_groups.delete(GROUP_NAME)
    
  2. To call the function that you previously added, add this code under the if statement at the end of the .py file:

    delete_resources(resource_group_client)
    
  3. Save myPythonProject.py.

Run the application

  1. To run the console application, click Start in Visual Studio.

  2. Press Enter after the status of each resource is returned. In the status information, you should see a Succeeded provisioning state. After the virtual machine is created, you have the opportunity to delete all the resources that you create. Before you press Enter to start deleting resources, you could take a few minutes to verify their creation in the Azure portal. If you have the Azure portal open, you might have to refresh the blade to see new resources.

    It should take about five minutes for this console application to run completely from start to finish. It may take several minutes after the application has finished before all the resources and the resource group are deleted.

Next steps