Azure Proactive Resiliency Library v2
Tools Glossary GitHub GitHub Issues Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

virtualMachines

Summary

RecommendationImpactCategoryAutomation AvailablePG Verified
Run production workloads on two or more VMs using VMSS FlexHighHigh AvailabilityYesVerified
Deploy VMs across Availability ZonesHighHigh AvailabilityYesVerified
Migrate VMs using availability sets to VMSS FlexHighHigh AvailabilityYesVerified
Replicate VMs using Azure Site RecoveryMediumDisaster RecoveryYesVerified
Use Managed Disks for VM disksHighHigh AvailabilityYesVerified
Host database data on a data diskLowScalabilityYesVerified
Backup VMs with Azure Backup serviceMediumDisaster RecoveryYesVerified
Review VMs in stopped stateLowGovernanceYesVerified
Enable Accelerated Networking (AccelNet)MediumScalabilityYesVerified
When AccelNet is enabled, you must manually update the GuestOS NIC driverLowGovernanceNoVerified
VMs should not have a Public IP directly associatedMediumSecurityYesVerified
VM network interfaces and associated subnets both have a Network Security Group associatedLowSecurityYesVerified
IP Forwarding should only be enabled for Network Virtual AppliancesMediumSecurityYesVerified
Customer DNS Servers should be configured in the Virtual Network levelLowOther Best PracticesYesVerified
Shared disks should only be enabled in clustered serversMediumOther Best PracticesYesVerified
Network access to the VM disk should be set to Disable public access and enable private accessLowSecurityYesVerified
Ensure that your VMs are compliant with Azure PoliciesLowGovernanceYesVerified
Virtual Machines should have Azure Disk Encryption or EncryptionAtHost enabledHighSecurityNoVerified
Enable VM InsightsLowMonitoring and AlertingYesVerified
Configure monitoring for all Azure Virtual MachinesLowMonitoring and AlertingYesVerified
Use maintenance configurations for the VMsHighHigh AvailabilityYesVerified
Don't use A or B-Series VMs for production needing constant full CPU performanceHighScalabilityYesVerified
Mission Critical Workloads should consider using Premium or Ultra DisksHighScalabilityYesVerified
Use Azure Boost VMs for Maintenance sensitive workloadMediumHigh AvailabilityNoVerified
Enable Scheduled Events for Maintenance sensitive workload VMsMediumHigh AvailabilityNoVerified
Use Azure Disks with Zone Redundant Storage for higher resiliency and availabilityMediumHigh AvailabilityYesVerified
Reserve Compute Capacity for critical workloadsHighHigh AvailabilityYesPreview

Details


Run production workloads on two or more VMs using VMSS Flex

Impact:  High Category:  High Availability PG Verified:  Verified

Description:

Production VM workloads should be deployed on multiple VMs and grouped in a VMSS Flex instance to intelligently distribute across the platform, minimizing the impact of platform faults and updates.

Potential Benefits:

Enhanced fault/update resilience
Learn More:
What has changed with Flexible orchestration mode
Attach or detach a Virtual Machine to or from a Virtual Machine Scale Set

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that are not associated with a VMSS Flex instance
resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnull(properties.virtualMachineScaleSet.id)
| project recommendationId="273f6b30-68e0-4241-85ea-acf15ffb60bf", name, id, tags



Deploy VMs across Availability Zones

Impact:  High Category:  High Availability PG Verified:  Verified

Description:

Azure Availability Zones, within each Azure region, are tolerant to local failures, protecting applications and data against unlikely Datacenter failures by being physically separate.

Potential Benefits:

Enhanced VM resilience to failures
Learn More:
Create virtual machines in an availability zone using the Azure portal

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that are not assigned to a Zone
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnull(zones)
| project recommendationId="2bd0be95-a825-6f47-a8c6-3db1fb5eb387", name, id, tags, param1="No Zone"



Migrate VMs using availability sets to VMSS Flex

Impact:  High Category:  High Availability PG Verified:  Verified

Description:

Availability sets will soon be retired. Migrate workloads from VMs to VMSS Flex for deployment across zones or within the same zone across different fault domains (FDs) and update domains (UDs) for better reliability.

Potential Benefits:

Enhances reliability and future-proofs VMs
Learn More:
Resiliency checklist for Virtual Machines

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs using Availability Sets
resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnotnull(properties.availabilitySet)
| project recommendationId = "a8d25876-7951-b646-b4e8-880c9031596b", name, id, tags, param1=strcat("availabilitySet: ",properties.availabilitySet.id)



Replicate VMs using Azure Site Recovery

Impact:  Medium Category:  Disaster Recovery PG Verified:  Verified

Description:

Replicating Azure VMs via Site Recovery entails continuous, asynchronous disk replication to a target region. Recovery points are generated every few minutes, ensuring a Recovery Point Objective (RPO) in minutes.

Potential Benefits:

Minimize downtime in disasters
Learn More:
Resiliency checklist for Virtual Machines
Run a test failover (disaster recovery drill) to Azure

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that do NOT have replication with ASR enabled
resources
| where type =~ "Microsoft.Compute/virtualMachines"
| extend securityType = iif(isnull(properties.securityProfile.securityType), "Standard", properties.securityProfile.securityType)
| where securityType !in~ ("TrustedLaunch", "ConfidentialVM")
| project id, vmIdForJoin = tolower(id), name, tags
| join kind = leftouter (
    recoveryservicesresources
    | where type =~ "Microsoft.RecoveryServices/vaults/replicationFabrics/replicationProtectionContainers/replicationProtectedItems"
        and properties.providerSpecificDetails.dataSourceInfo.datasourceType =~ "AzureVm"
    | project vmResourceId = tolower(properties.providerSpecificDetails.dataSourceInfo.resourceId)
    )
    on $left.vmIdForJoin == $right.vmResourceId
| where isempty(vmResourceId)
| project recommendationId = "cfe22a65-b1db-fd41-9e8e-d573922709ae", name, id, tags


Use Managed Disks for VM disks

Impact:  High Category:  High Availability PG Verified:  Verified

Description:

Azure is retiring unmanaged disks on September 30, 2025. Users should plan the migration to avoid disruptions and maintain service reliability.

Potential Benefits:

Avoid retirement disruption, enhance reliability
Learn More:
Migrate your Azure unmanaged disks by Sep 30, 2025
Migrate Windows VM from unmanaged disks to managed disks
Migrate Linux VM from unmanaged disks to managed disks

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that are not using Managed Disks
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnull(properties.storageProfile.osDisk.managedDisk)
| project recommendationId = "122d11d7-b91f-8747-a562-f56b79bcfbdc", name, id, tags



Host database data on a data disk

Impact:  Low Category:  Scalability PG Verified:  Verified

Description:

A data disk is a managed disk attached to a virtual machine for storing database or other essential data. These disks are SCSI drives labeled as per choice.

Potential Benefits:

Enhances performance, recovery, migration flexibility
Learn More:
Introduction to Azure managed disks - Data disks
Azure managed disk types

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that only have OS Disk
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where array_length(properties.storageProfile.dataDisks) < 1
| project recommendationId = "4ea2878f-0d69-8d4a-b715-afc10d1e538e", name, id, tags



Backup VMs with Azure Backup service

Impact:  Medium Category:  Disaster Recovery PG Verified:  Verified

Description:

Enable backups for your virtual machines with Azure Backup to secure and quickly recover your data. This service offers simple, secure, and cost-effective solutions for backing up and recovering data from the Microsoft Azure cloud.

Potential Benefits:

Secure data recovery and backup
Learn More:
What is the Azure Backup service?

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that do NOT have Backup enabled
// Run query to see results.
resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| project name, id, tags
| join kind=leftouter (
    recoveryservicesresources
    | where type =~ 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems'
    | where properties.dataSourceInfo.datasourceType =~ 'Microsoft.Compute/virtualMachines'
    | project idBackupEnabled=properties.sourceResourceId
    | extend name=strcat_array(array_slice(split(idBackupEnabled, '/'), 8, -1), '/')
) on name
| where isnull(idBackupEnabled)
| project-away idBackupEnabled
| project-away name1
| project recommendationId = "1981f704-97b9-b645-9c57-33f8ded9261a", name, id, tags
| order by id asc



Review VMs in stopped state

Impact:  Low Category:  Governance PG Verified:  Verified

Description:

Azure Virtual Machines (VM) instances have various states, like provisioning and power states. A non-running VM may indicate issues or it being unnecessary, suggesting removal could help cut costs.

Potential Benefits:

Reduce costs by removing unused VMs
Learn More:
States and billing status of Azure Virtual Machines

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that are NOT running
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where properties.extended.instanceView.powerState.displayStatus != 'VM running'
| project recommendationId = "98b334c0-8578-6046-9e43-b6e8fce6318e", name, id, tags



Enable Accelerated Networking (AccelNet)

Impact:  Medium Category:  Scalability PG Verified:  Verified

Description:

Accelerated networking enables SR-IOV to a VM, greatly improving its networking performance by bypassing the host from the data path, which reduces latency, jitter, and CPU utilization for demanding network workloads on supported VM types.

Potential Benefits:

Reduces latency, jitter and CPU use
Learn More:
Accelerated Networking (AccelNet) overview

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VM NICs that do not have Accelerated Networking enabled
resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| mv-expand nic = properties.networkProfile.networkInterfaces
| project name, id, tags, lowerCaseNicId = tolower(nic.id), vmSize = tostring(properties.hardwareProfile.vmSize)
| join kind = inner (
    resources
    | where type =~ 'Microsoft.Network/networkInterfaces'
    | where properties.enableAcceleratedNetworking == false
    | project nicName = split(id, "/")[8], lowerCaseNicId = tolower(id)
    )
    on lowerCaseNicId
| summarize nicNames = make_set(nicName) by name, id, tostring(tags), vmSize
| extend param1 = strcat("NicName: ", strcat_array(nicNames, ", ")), param2 = strcat("VMSize: ", vmSize)
| project recommendationId = "dfedbeb1-1519-fc47-86a5-52f96cf07105", name, id, tags, param1, param2
| order by id asc



When AccelNet is enabled, you must manually update the GuestOS NIC driver

Impact:  Low Category:  Governance PG Verified:  Verified

Description:

When Accelerated Networking is enabled, the default Azure VNet interface in GuestOS is swapped for a Mellanox, and its driver comes from a 3rd party. Marketplace images have the latest Mellanox drivers, but post-deployment, updating the driver is the user's responsibility.

Potential Benefits:

Enhanced VM network efficiency
Learn More:
Accelerated Networking (AccelNet) overview

ARG Query:

Click the Azure Resource Graph tab to view the query

// cannot-be-validated-with-arg



VMs should not have a Public IP directly associated

Impact:  Medium Category:  Security PG Verified:  Verified

Description:

For outbound internet connectivity of Virtual Machines, using NAT Gateway or Azure Firewall is recommended to enhance security and service resilience, thanks to their higher availability and SNAT ports.

Potential Benefits:

Enhanced security and service resiliency
Learn More:
Use Source Network Address Translation (SNAT) for outbound connections

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs with PublicIPs directly associated with them
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnotnull(properties.networkProfile.networkInterfaces)
| mv-expand nic=properties.networkProfile.networkInterfaces
| project name, id, tags, nicId = nic.id
| extend nicId = tostring(nicId)
| join kind=inner (
    Resources
    | where type =~ 'Microsoft.Network/networkInterfaces'
    | where isnotnull(properties.ipConfigurations)
    | mv-expand ipconfig=properties.ipConfigurations
    | extend publicIp = tostring(ipconfig.properties.publicIPAddress.id)
    | where publicIp != ""
    | project name, nicId = tostring(id), publicIp
) on nicId
| project recommendationId = "1f629a30-c9d0-d241-82ee-6f2eb9d42cb4", name, id, tags
| order by id asc



VM network interfaces and associated subnets both have a Network Security Group associated

Impact:  Low Category:  Security PG Verified:  Verified

Description:

Unless you have a specific reason, it's advised to associate a network security group to a subnet or a network interface, but not both, to avoid unexpected communication issues and troubleshooting due to potential rule conflicts between the two associations.

Potential Benefits:

Reduces communication problems
Learn More:
How network security groups filter network traffic

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Provides a list of virtual machines and associated NICs that do have an NSG associated to them and also an NSG associated to the subnet.
Resources
| where type =~ 'Microsoft.Network/networkInterfaces'
| where isnotnull(properties.networkSecurityGroup)
| mv-expand ipConfigurations = properties.ipConfigurations, nsg = properties.networkSecurityGroup
| project nicId = tostring(id), subnetId = tostring(ipConfigurations.properties.subnet.id), nsgName=split(nsg.id, '/')[8]
| parse kind=regex subnetId with '/virtualNetworks/' virtualNetwork '/subnets/' subnet
    | join kind=inner (
        Resources
        | where type =~ 'Microsoft.Network/NetworkSecurityGroups' and isnotnull(properties.subnets)
        | project name, resourceGroup, subnet=properties.subnets
        | mv-expand subnet
        | project subnetId=tostring(subnet.id)
    ) on subnetId
    | project nicId
| join kind=leftouter (
    Resources
    | where type =~ 'Microsoft.Compute/virtualMachines'
    | where isnotnull(properties.networkProfile.networkInterfaces)
    | mv-expand nic=properties.networkProfile.networkInterfaces
    | project vmName = name, vmId = id, tags, nicId = nic.id, nicName=split(nic.id, '/')[8]
    | extend nicId = tostring(nicId)
) on nicId
| project recommendationId = "82b3cf6b-9ae2-2e44-b193-10793213f676", name=vmName, id = vmId, tags, param1 = strcat("nic-name=", nicName)



IP Forwarding should only be enabled for Network Virtual Appliances

Impact:  Medium Category:  Security PG Verified:  Verified

Description:

IP forwarding allows a virtual machine network interface to receive and send network traffic not destined for or originating from its assigned IP addresses.

Potential Benefits:

Enhances network appliance function
Learn More:
Enable or disable IP forwarding

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VM NICs that have IPForwarding enabled. This feature is usually only required for Network Virtual Appliances
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnotnull(properties.networkProfile.networkInterfaces)
| mv-expand nic=properties.networkProfile.networkInterfaces
| project name, id, tags, nicId = nic.id
| extend nicId = tostring(nicId)
| join kind=inner (
    Resources
    | where type =~ 'Microsoft.Network/networkInterfaces'
    | where properties.enableIPForwarding == true
    | project nicId = tostring(id)
) on nicId
| project recommendationId = "41a22a5e-5e08-9647-92d0-2ffe9ef1bdad", name, id, tags
| order by id asc



Customer DNS Servers should be configured in the Virtual Network level

Impact:  Low Category:  Other Best Practices PG Verified:  Verified

Description:

Configure the DNS Server at the Virtual Network level to prevent any inconsistency across the environment.

Potential Benefits:

Ensures DNS consistency
Learn More:
Name resolution for resources in Azure virtual networks

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VM NICs that have DNS Server settings configured in any of the NICs
Resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnotnull(properties.networkProfile.networkInterfaces)
| mv-expand nic=properties.networkProfile.networkInterfaces
| project name, id, tags, nicId = nic.id
| extend nicId = tostring(nicId)
| join kind=inner (
    Resources
    | where type =~ 'Microsoft.Network/networkInterfaces'
    | project name, id, dnsServers = properties.dnsSettings.dnsServers
    | extend hasDns = array_length(dnsServers) >= 1
    | where hasDns != 0
    | project name, nicId = tostring(id)
) on nicId
| project recommendationId = "1cf8fe21-9593-1e4e-966b-779a294c0d30", name, id, tags
| order by id asc



Shared disks should only be enabled in clustered servers

Impact:  Medium Category:  Other Best Practices PG Verified:  Verified

Description:

Azure shared disks let you attach a disk to multiple VMs at once for deploying or migrating clustered applications, suitable only when a disk is shared among VM cluster members.

Potential Benefits:

Enhances clustered server performance
Learn More:
Azure Shared Disk Introduction
Enable Shared Disks

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all Disks configured to be Shared. This is not an indication of an issue, but if a disk with this configuration is assigned to two or more VMs without a proper disk control mechanism (like a WSFC) it can lead to data loss
resources
| where type =~ 'Microsoft.Compute/disks'
| where isnotnull(properties.maxShares) and properties.maxShares >= 2
| project id, name, tags, lowerCaseDiskId = tolower(id), diskState = tostring(properties.diskState)
| join kind = leftouter (
    resources
    | where type =~ 'Microsoft.Compute/virtualMachines'
    | project osDiskVmName = name, lowerCaseOsDiskId = tolower(properties.storageProfile.osDisk.managedDisk.id)
    | join kind = fullouter (
        resources
        | where type =~ 'Microsoft.Compute/virtualMachines'
        | mv-expand dataDisks = properties.storageProfile.dataDisks
        | project dataDiskVmName = name, lowerCaseDataDiskId = tolower(dataDisks.managedDisk.id)
        )
        on $left.lowerCaseOsDiskId == $right.lowerCaseDataDiskId
    | project lowerCaseDiskId = coalesce(lowerCaseOsDiskId, lowerCaseDataDiskId), vmName = coalesce(osDiskVmName, dataDiskVmName)
    )
    on lowerCaseDiskId
| summarize vmNames = make_set(vmName) by name, id, tostring(tags), diskState
| extend param1 = strcat("DiskState: ", diskState), param2 = iif(isempty(vmNames[0]), "VMName: n/a", strcat("VMName: ", strcat_array(vmNames, ", ")))
| project recommendationId = "3263a64a-c256-de48-9818-afd3cbc55c2a", name, id, tags, param1, param2
| order by id asc



Network access to the VM disk should be set to Disable public access and enable private access

Impact:  Low Category:  Security PG Verified:  Verified

Description:

Recommended changing to "Disable public access and enable private access" and creating a Private Endpoint to improve security by restricting direct public access and ensuring connections are made privately, enhancing data protection and minimizing potential external threats.

Potential Benefits:

Enhances VM security and privacy
Learn More:
Restrict import/export access for managed disks using Azure Private Link

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all Disks with "Enable public access from all networks" enabled
resources
| where type =~ 'Microsoft.Compute/disks'
| where properties.publicNetworkAccess == "Enabled"
| project id, name, tags, lowerCaseDiskId = tolower(id)
| join kind = leftouter (
    resources
    | where type =~ 'Microsoft.Compute/virtualMachines'
    | project osDiskVmName = name, lowerCaseOsDiskId = tolower(properties.storageProfile.osDisk.managedDisk.id)
    | join kind = fullouter (
        resources
        | where type =~ 'Microsoft.Compute/virtualMachines'
        | mv-expand dataDisks = properties.storageProfile.dataDisks
        | project dataDiskVmName = name, lowerCaseDataDiskId = tolower(dataDisks.managedDisk.id)
        )
        on $left.lowerCaseOsDiskId == $right.lowerCaseDataDiskId
    | project lowerCaseDiskId = coalesce(lowerCaseOsDiskId, lowerCaseDataDiskId), vmName = coalesce(osDiskVmName, dataDiskVmName)
    )
    on lowerCaseDiskId
| summarize vmNames = make_set(vmName) by name, id, tostring(tags)
| extend param1 = iif(isempty(vmNames[0]), "VMName: n/a", strcat("VMName: ", strcat_array(vmNames, ", ")))
| project recommendationId = "70b1d2be-e6c4-b54e-9959-b1b690f9e485", name, id, tags, param1
| order by id asc



Ensure that your VMs are compliant with Azure Policies

Impact:  Low Category:  Governance PG Verified:  Verified

Description:

Keeping your virtual machine (VM) secure is crucial for the applications you run. This involves using various Azure services and features to ensure secure access to your VMs and the secure storage of your data, aiming for overall security of your VM and applications.

Potential Benefits:

Secure VMs and applications
Learn More:
Policy-driven governance
Azure Policy Regulatory Compliance controls for Azure Virtual Machines

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs in "Non-compliant" state with Azure Policies
policyresources
| where type =~ "Microsoft.PolicyInsights/policyStates" and properties.resourceType =~ "Microsoft.Compute/virtualMachines" and properties.complianceState =~ "NonCompliant"
| project
    policyDefinitionId = tolower(properties.policyDefinitionId),
    policyAssignmentId = tolower(properties.policyAssignmentId),
    targetResourceId = tolower(properties.resourceId)
// Join the policy definition details
| join kind = leftouter (
    policyresources
    | where type =~ "Microsoft.Authorization/policyDefinitions"
    | project policyDefinitionId = tolower(id), policyDefinitionDisplayName = properties.displayName
    )
    on policyDefinitionId
| project policyDefinitionId, policyDefinitionDisplayName, policyAssignmentId, targetResourceId
// Join the policy assignment details
| join kind = leftouter (
    policyresources
    | where type =~ "Microsoft.Authorization/policyAssignments"
    | project policyAssignmentId = tolower(id), policyAssignmentDisplayName = properties.displayName
    )
    on policyAssignmentId
| project policyDefinitionId, policyDefinitionDisplayName, policyAssignmentId, policyAssignmentDisplayName, targetResourceId
// Join the target resource details
| join kind = leftouter (
    resources
    | where type =~ "Microsoft.Compute/virtualMachines"
    | project targetResourceId = tolower(id), targetResourceIdPreservedCase = id, targetResourceName = name, targetResourceTags = tags
    )
    on targetResourceId
| project
    recommendationId = "c42343ae-2712-2843-a285-3437eb0b28a1",
    name = targetResourceName,
    id = targetResourceIdPreservedCase,
    tags = targetResourceTags,
    param1 = strcat("DefinitionName: ", policyDefinitionDisplayName),
    param2 = strcat("DefinitionID: ", policyDefinitionId),
    param3 = strcat("AssignmentName: ", policyAssignmentDisplayName),
    param4 = strcat("AssignmentID: ", policyAssignmentId)


Virtual Machines should have Azure Disk Encryption or EncryptionAtHost enabled

Impact:  High Category:  Security PG Verified:  Verified

Description:

Consider enabling Azure Disk Encryption (ADE) for encrypting Azure VM disks using DM-Crypt (Linux) or BitLocker (Windows). Additionally, consider Encryption at host and Confidential disk encryption for enhanced data security.

Potential Benefits:

Enhances data security and integrity
Learn More:
Overview of managed disk encryption options

ARG Query:

Click the Azure Resource Graph tab to view the query

// under-development



Enable VM Insights

Impact:  Low Category:  Monitoring and Alerting PG Verified:  Verified

Description:

VM Insights monitors VM and scale set performance, health, running processes, and dependencies. It enhances the predictability of application performance and availability by pinpointing performance bottlenecks and network issues, and it clarifies if problems are related to other dependencies.

Potential Benefits:

Improves VM performance and health
Learn More:
Overview of VM insights
Did the extension install properly?

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Check for VMs without Azure Monitoring Agent extension installed, missing Data Collection Rule or Data Collection Rule without performance enabled.
Resources
| where type == 'microsoft.compute/virtualmachines'
| project idVm = tolower(id), name, tags
| join kind=leftouter (
    InsightsResources
    | where type =~ "Microsoft.Insights/dataCollectionRuleAssociations" and id has "Microsoft.Compute/virtualMachines"
    | project idDcr = tolower(properties.dataCollectionRuleId), idVmDcr = tolower(substring(id, 0, indexof(id, "/providers/Microsoft.Insights/dataCollectionRuleAssociations/"))))
on $left.idVm == $right.idVmDcr
| join kind=leftouter (
    Resources
    | where type =~ "Microsoft.Insights/dataCollectionRules"
    | extend
        isPerformanceEnabled = iif(properties.dataSources.performanceCounters contains "Microsoft-InsightsMetrics" and properties.dataFlows contains "Microsoft-InsightsMetrics", true, false),
        isMapEnabled = iif(properties.dataSources.extensions contains "Microsoft-ServiceMap" and properties.dataSources.extensions contains "DependencyAgent" and properties.dataFlows contains "Microsoft-ServiceMap", true, false)//,
    | where isPerformanceEnabled or isMapEnabled
    | project dcrName = name, isPerformanceEnabled, isMapEnabled, idDcr = tolower(id))
on $left.idDcr == $right.idDcr
| join kind=leftouter (
    Resources
        | where type == 'microsoft.compute/virtualmachines/extensions' and (name contains 'AzureMonitorWindowsAgent' or name contains 'AzureMonitorLinuxAgent')
        | extend idVmExtension = tolower(substring(id, 0, indexof(id, '/extensions'))), extensionName = name)
on $left.idVm == $right.idVmExtension
| where isPerformanceEnabled != 1 or (extensionName != 'AzureMonitorWindowsAgent' and extensionName != 'AzureMonitorLinuxAgent')
| project recommendationId = "b72214bb-e879-5f4b-b9cd-642db84f36f4", name, id = idVm, tags, param1 = strcat('MonitoringExtension:', extensionName), param2 = strcat('DataCollectionRuleId:', idDcr), param3 = strcat('isPerformanceEnabled:', isPerformanceEnabled)



Configure monitoring for all Azure Virtual Machines

Impact:  Low Category:  Monitoring and Alerting PG Verified:  Verified

Description:

Azure Monitor Metrics automatically receives platform metrics, but platform logs, which offer detailed diagnostics and auditing for resources and their Azure platform, need to be manually routed for collection.

Potential Benefits:

Enhanced diagnostics and auditing capability
Learn More:
Azure Monitor Agent overview

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all Virtual Machines without diagnostic settings enabled/with diagnostic settings enabled but not configured both performance counters and event logs/syslogs.
resources
| where type =~ "microsoft.compute/virtualmachines"
| project name, id, tags, lowerCaseVmId = tolower(id)
| join kind = leftouter (
    resources
    | where type =~ "Microsoft.Compute/virtualMachines/extensions" and properties.publisher =~ "Microsoft.Azure.Diagnostics"
    | project
        lowerCaseVmIdOfExtension = tolower(substring(id, 0, indexof(id, "/extensions/"))),
        extensionType = properties.type,
        provisioningState = properties.provisioningState,
        storageAccount = properties.settings.StorageAccount,
        // Windows
        wadPerfCounters = properties.settings.WadCfg.DiagnosticMonitorConfiguration.PerformanceCounters.PerformanceCounterConfiguration,
        wadEventLogs = properties.settings.WadCfg.DiagnosticMonitorConfiguration.WindowsEventLog,
        // Linux
        ladPerfCounters = properties.settings.ladCfg.diagnosticMonitorConfiguration.performanceCounters.performanceCounterConfiguration,
        ladSyslog = properties.settings.ladCfg.diagnosticMonitorConfiguration.syslogEvents
    | extend
        // Windows
        isWadPerfCountersConfigured = iif(array_length(wadPerfCounters) > 0, true, false),
        isWadEventLogsConfigured = iif(isnotnull(wadEventLogs) and array_length(wadEventLogs.DataSource) > 0, true, false),
        // Linux
        isLadPerfCountersConfigured = iif(array_length(ladPerfCounters) > 0, true, false),
        isLadSyslogConfigured = isnotnull(ladSyslog)
    | project
        lowerCaseVmIdOfExtension,
        extensionType,
        provisioningState,
        storageAccount,
        isPerfCountersConfigured = case(extensionType =~ "IaaSDiagnostics", isWadPerfCountersConfigured, extensionType =~ "LinuxDiagnostic", isLadPerfCountersConfigured, false),
        isEventLogsConfigured = case(extensionType =~ "IaaSDiagnostics", isWadEventLogsConfigured, extensionType =~ "LinuxDiagnostic", isLadSyslogConfigured, false)
    )
    on $left.lowerCaseVmId == $right.lowerCaseVmIdOfExtension
| where isempty(lowerCaseVmIdOfExtension) or provisioningState !~ "Succeeded" or not(isPerfCountersConfigured and isEventLogsConfigured)
| extend
    param1 = strcat("DiagnosticSetting: ", iif(isnotnull(extensionType), strcat("Enabled, partially configured (", extensionType, ")"), "Not enabled")),
    param2 = strcat("ProvisioningState: ", iif(isnotnull(provisioningState), provisioningState, "n/a")),
    param3 = strcat("storageAccount: ", iif(isnotnull(storageAccount), storageAccount, "n/a")),
    param4 = strcat("PerformanceCounters: ", case(isnull(isPerfCountersConfigured), "n/a", isPerfCountersConfigured, "Configured", "Not configured")),
    param5 = strcat("EventLogs/Syslogs: ", case(isnull(isEventLogsConfigured), "n/a", isEventLogsConfigured, "Configured", "Not configured"))
| project recommendationId = "4a9d8973-6dba-0042-b3aa-07924877ebd5", name, id, tags, param1, param2, param3, param4, param5



Use maintenance configurations for the VMs

Impact:  High Category:  High Availability PG Verified:  Verified

Description:

The maintenance configuration settings let users schedule and manage updates, making sure the updates or interruptions on the VM are performed within a planned timeframe.

Potential Benefits:

Scheduled updates for VMs
Learn More:
Use maintenance configurations to control and manage the VM updates

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find VMS that do not have maintenance configuration assigned
Resources
| extend resourceId = tolower(id)
| project name, location, type, id, tags, resourceId, properties
| where type =~ 'Microsoft.Compute/virtualMachines'
| join kind=leftouter (
maintenanceresources
| where type =~ "microsoft.maintenance/configurationassignments"
| project planName = name, type, maintenanceProps = properties
| extend resourceId = tostring(maintenanceProps.resourceId)
) on resourceId
| where isnull(maintenanceProps)
| project recommendationId = "52ab9e5c-eec0-3148-8bd7-b6dd9e1be870",name, id, tags
| order by id asc



Don't use A or B-Series VMs for production needing constant full CPU performance

Impact:  High Category:  Scalability PG Verified:  Verified

Description:

A-series VMs are tailored for entry-level workloads like development and testing, including use cases such as development and test servers, low traffic web servers, and small to medium databases.

Potential Benefits:

Ensures full CPU usage for heavy tasks
Learn More:
B-series burstable virtual machine sizes

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs using A or B series families
resources
| where type == 'microsoft.compute/virtualmachines'
| where properties.hardwareProfile.vmSize contains "Standard_B" or properties.hardwareProfile.vmSize contains "Standard_A"
| project recommendationId = "3201dba8-d1da-4826-98a4-104066545170", name, id, tags, param1=strcat("vmSku: " , properties.hardwareProfile.vmSize)



Mission Critical Workloads should consider using Premium or Ultra Disks

Impact:  High Category:  Scalability PG Verified:  Verified

Description:

Compared to Standard HDD and SSD, Premium SSD, SSDv2, and Ultra SSDs offer improved performance, configurability, and higher single-instance Virtual Machine uptime SLAs. The lowest SLA of all disks on a Virtual Machine applies, so it is best to use Premium or Ultra Disks for the highest uptime SLA.

Potential Benefits:

Enhanced performance, cost efficiency, and uptime SLA
Learn More:
Disk type comparison and decision tree

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all VMs that have an attached disk that is not in the Premium or Ultra sku tier.

resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| extend lname = tolower(name)
| join kind=leftouter(resources
    | where type =~ 'Microsoft.Compute/disks'
    | where not(sku.tier =~ 'Premium') and not(sku.tier =~ 'Ultra')
    | extend lname = tolower(tostring(split(managedBy, '/')[8]))
    | project lname, name
    | summarize disks = make_list(name) by lname) on lname
| where isnotnull(disks)
| project recommendationId = "df0ff862-814d-45a3-95e4-4fad5a244ba6", name, id, tags, param1=strcat("AffectedDisks: ", disks)



Use Azure Boost VMs for Maintenance sensitive workload

Impact:  Medium Category:  High Availability PG Verified:  Verified

Description:

If the workload is Maintenance sensitive, consider Azure Boost compatible VMs. Azure Boost is designed to lessen the impact on customers when Azure maintenance activities occur on the host, and the current list of compatible VM sizes are documented in the first link below.

Potential Benefits:

Less maintenance impact
Learn More:
Microsoft Azure Boost
Announcing the general availability of Azure Boost

ARG Query:

Click the Azure Resource Graph tab to view the query

// under-development



Enable Scheduled Events for Maintenance sensitive workload VMs

Impact:  Medium Category:  High Availability PG Verified:  Verified

Description:

If your workload is Maintenance sensitive, enable Scheduled Events. This Azure Metadata Service lets your app prepare for virtual machine maintenance by providing information on upcoming events like reboots, reducing disruptions.

Potential Benefits:

Minimize downtime for VMs
Learn More:
Monitor scheduled events for your Azure VMs
Azure Metadata Service Scheduled Events for Linux VMs
Azure Metadata Service Scheduled Events for Windows VMs

ARG Query:

Click the Azure Resource Graph tab to view the query

// under-development



Use Azure Disks with Zone Redundant Storage for higher resiliency and availability

Impact:  Medium Category:  High Availability PG Verified:  Verified

Description:

Azure disks offers a zone-redundant storage (ZRS) option for workloads that need to be resilient to an entire zone being down. Due to the cross-zone data replication, ZRS disks have higher write latency when compared to the locally-redundant option (LRS), so make sure to benchmark your disks.

Potential Benefits:

Enhanced Disk resilience to failures
Learn More:
Redundancy options for managed disks

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find eligible Disks that are not zonal nor zone redundant
resources
| where type == 'microsoft.compute/disks'
| where sku has "Premium_LRS" or sku has "StandardSSD_LRS"
| where sku.name has_cs 'ZRS' or array_length(zones) > 0
| project recommendationId="fa0cf4f5-0b21-47b7-89a9-ee936f193ce1", name, id, tags, param1 = sku, param2 = sku.name


Reserve Compute Capacity for critical workloads

Impact:  High Category:  High Availability PG Verified:  Preview

Description:

Azure Capacity Reservations ensure high availability for virtual machines by reserving compute capacity in advance within a specific region or availability zone. This guarantees that VMs will have the necessary resources during peak demand or maintenance events, enhancing reliability and uptime.

Potential Benefits:

Guaranteed capacity in constrained regions/zones
Learn More:
On-demand Capacity Reservation

ARG Query:

Click the Azure Resource Graph tab to view the query

// Azure Resource Graph Query
// Find all Virtual Machines not associated with a Capacity Reservation, and provide details for Capacity Reservation like vmSize, location, and zone.
resources
| where type =~ 'Microsoft.Compute/virtualMachines'
| where isnull(properties.capacityReservation)
| extend zoneValue = iff(isnull(zones), "null", zones)
| project recommendationId = "302fda08-ee65-4fbe-a916-6dc0b33169c4", name, id, tags, param1 = strcat("VmSize: ", properties.hardwareProfile.vmSize), param2 = strcat("Location: ", location), param3 = strcat("Zone: ", zoneValue)