  def GetOrCreateAnalysisVm(
      self,
      vm_name: str,
      boot_disk_size: int,
      cpu_cores: int,
      memory_in_mb: int,
      ssh_public_key: str,
      region: Optional[str] = None,
      packages: Optional[List[str]] = None,
      tags: Optional[Dict[str, str]] = None
  ) -> Tuple['AZComputeVirtualMachine', bool]:
    """Get or create a new virtual machine for analysis purposes.

    Args:
      vm_name (str): The instance name tag of the virtual machine.
      boot_disk_size (int): The size of the analysis VM boot volume (in GB).
      cpu_cores (int): Number of CPU cores for the analysis VM.
      memory_in_mb (int): The memory size (in MB) for the analysis VM.
      ssh_public_key (str): A SSH public key data to associate with the
          VM. This must be provided as otherwise the VM will not be
          accessible.
      region (str): Optional. The region in which to create the vm. If not
          provided, the vm will be created in the default_region
          associated to the AZAccount object.
      packages (List[str]): Optional. List of packages to install in the VM.
      tags (Dict[str, str]): Optional. A dictionary of tags to add to the
          instance, for example {'TicketID': 'xxx'}. An entry for the
          instance name is added by default.

    Returns:
      Tuple[AZComputeVirtualMachine, bool]: A tuple with an
          AZComputeVirtualMachine object and a boolean indicating if the
          virtual machine was created (True) or reused (False).

    Raises:
      RuntimeError: If the provided SSH key is invalid.
      ResourceCreationError: If the virtual machine cannot be found or created.
    """

    # Re-use instance if it already exists, or create a new one.
    try:
      instance = self.GetInstance(vm_name)
      if instance:
        created = False
        return instance, created
    except errors.ResourceNotFoundError:
      pass

    # Validate SSH public key format
    try:
      sshpubkeys.SSHKey(ssh_public_key, strict=True).parse()
    except sshpubkeys.InvalidKeyError as exception:
      raise RuntimeError('The provided public SSH key is invalid: '
                         '{0:s}'.format(str(exception))) from exception

    instance_type = self._GetInstanceType(
        cpu_cores, memory_in_mb, premium_io=True, region=region)
    startup_script = utils.ReadStartupScript(utils.FORENSICS_STARTUP_SCRIPT_AZ)
    if packages:
      startup_script = startup_script.replace('${packages[@]}', ' '.join(
          packages))

    if not region:
      region = self.az_account.default_region

    creation_data = {
        'location': region,
        'properties': {
            'hardwareProfile': {'vmSize': instance_type},
            'storageProfile': {
                'imageReference': {
                    'sku': common.UBUNTU_2204_SKU,
                    'publisher': 'Canonical',
                    'version': 'latest',
                    'offer': '0001-com-ubuntu-server-jammy'}
            },
            'osDisk': {
                'caching': 'ReadWrite',
                'managedDisk': {'storageAccountType': 'Standard_LRS'},
                'name': 'os-disk-{0:s}'.format(vm_name),
                'diskSizeGb': boot_disk_size,
                'createOption': models.DiskCreateOption.from_image
            },
            'osProfile': {
                'adminUsername': 'AzureUser',
                'computerName': vm_name,
                # Azure requires the startup script to be sent as a b64 string
                'customData': base64.b64encode(
                    str.encode(startup_script)).decode('utf-8'),
                'linuxConfiguration': {
                    'ssh': {
                        'publicKeys': [{
                            'path': '/home/AzureUser/.ssh/authorized_keys',
                            'keyData': ssh_public_key}]
                    }
                }
            },
            'networkProfile': {
                'networkInterfaces': [
                    # pylint: disable=line-too-long
                    # This is necessary when creating a VM from the SDK.
                    # See https://docs.microsoft.com/en-us/azure/virtual-machines/windows/python
                    # pylint: enable=line-too-long
                    {'id': self.az_account.network.CreateNetworkInterface(
                        vm_name, region)}
                ]
            }
        }
    }  # type: Dict[str, Any]

    if tags:
      creation_data['tags'] = tags

    try:
      request = self.compute_client.virtual_machines.begin_create_or_update(
          self.az_account.default_resource_group_name,
          vm_name,
          creation_data
      )
      while not request.done():
        sleep(5)  # Wait 5 seconds before checking disk status again
      vm = request.result()
    except azure_exceptions.CloudError as exception:
      raise errors.ResourceCreationError(
          'Could not create instance {0:s}: {1!s}'.format(vm_name, exception),
          __name__) from exception

    instance = AZComputeVirtualMachine(self.az_account,
                                       vm.id,
                                       vm.name,
                                       vm.location,
                                       zones=vm.zones)
    created = True
    return instance, created
Get or create a new virtual machine for analysis purposes.

Args:
vm_name (str): The instance name tag of the virtual machine.
boot_disk_size (int): The size of the analysis VM boot volume (in GB).
cpu_cores (int): Number of CPU cores for the analysis VM.
memory_in_mb (int): The memory size (in MB) for the analysis VM.
ssh_public_key (str): A SSH public key data to associate with the
VM. This must be provided as otherwise the VM will not be
accessible.
region (str): Optional. The region in which to create the vm. If not
provided, the vm will be created in the default_region
associated to the AZAccount object.
packages (List[str]): Optional. List of packages to install in the VM.
tags (Dict[str, str]): Optional. A dictionary of tags to add to the
instance, for example {'TicketID': 'xxx'}. An entry for the
instance name is added by default.

Returns:
Tuple[AZComputeVirtualMachine, bool]: A tuple with an
AZComputeVirtualMachine object and a boolean indicating if the
virtual machine was created (True) or reused (False).

Raises:
RuntimeError: If the provided SSH key is invalid.
ResourceCreationError: If the virtual machine cannot be found or created.
libcloudforensics/providers/azure/internal/compute.py