Skip to content
Back to Blog
1 min read

Azure Automanage: Automated VM Management Best Practices

What is Azure Automanage?

Automanage provides automated:

  • Configuration: Apply Microsoft best practices automatically
  • Updates: Windows Update and Azure Update Management
  • Backup: Azure Backup configuration
  • Monitoring: Azure Monitor and diagnostics
  • Security: Microsoft Defender for Cloud

Enabling Automanage

Azure Portal / CLI

# Enable Automanage for a VM
az automanage configuration-profile-assignment create \
    --resource-group rg-vms \
    --vm-name vm-web-01 \
    --configuration-profile Production

# Enable for multiple VMs
vms=("vm-web-01" "vm-web-02" "vm-app-01")
for vm in "${vms[@]}"; do
    az automanage configuration-profile-assignment create \
        --resource-group rg-vms \
        --vm-name $vm \
        --configuration-profile Production
done

# Check status
az automanage configuration-profile-assignment show \
    --resource-group rg-vms \
    --vm-name vm-web-01

Bicep Template

param vmName string
param location string = resourceGroup().location
param profile string = 'Production'

resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' existing = {
  name: vmName
}

resource automanageAssignment 'Microsoft.Automanage/configurationProfileAssignments@2021-04-30-preview' = {
  name: 'default'
  scope: vm
  properties: {
    configurationProfile: '/providers/Microsoft.Automanage/bestPractices/${profile}'
  }
}

At Scale with Azure Policy

{
  "mode": "Indexed",
  "policyRule": {
    "if": {
      "allOf": [
        {
          "field": "type",
          "equals": "Microsoft.Compute/virtualMachines"
        },
        {
          "field": "tags.Environment",
          "equals": "Production"
        },
        {
          "anyOf": [
            {
              "field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.offer",
              "like": "WindowsServer*"
            },
            {
              "field": "Microsoft.Compute/virtualMachines/storageProfile.imageReference.offer",
              "like": "*-LTS"
            }
          ]
        }
      ]
    },
    "then": {
      "effect": "deployIfNotExists",
      "details": {
        "type": "Microsoft.Automanage/configurationProfileAssignments",
        "name": "default",
        "existenceCondition": {
          "field": "Microsoft.Automanage/configurationProfileAssignments/configurationProfile",
          "equals": "/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction"
        },
        "roleDefinitionIds": [
          "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
        ],
        "deployment": {
          "properties": {
            "mode": "incremental",
            "template": {
              "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
              "contentVersion": "1.0.0.0",
              "parameters": {
                "vmName": {
                  "type": "string"
                },
                "location": {
                  "type": "string"
                }
              },
              "resources": [
                {
                  "type": "Microsoft.Compute/virtualMachines/providers/configurationProfileAssignments",
                  "apiVersion": "2021-04-30-preview",
                  "name": "[concat(parameters('vmName'), '/Microsoft.Automanage/default')]",
                  "properties": {
                    "configurationProfile": "/providers/Microsoft.Automanage/bestPractices/AzureBestPracticesProduction"
                  }
                }
              ]
            },
            "parameters": {
              "vmName": {
                "value": "[field('name')]"
              },
              "location": {
                "value": "[field('location')]"
              }
            }
          }
        }
      }
    }
  }
}

Custom Configuration Profiles

Create Custom Profile

# Create custom profile
az automanage configuration-profile create \
    --name "CustomWebServerProfile" \
    --resource-group rg-automanage \
    --configuration '{
        "Antimalware/Enable": true,
        "Antimalware/RealtimeProtectionEnabled": true,
        "AzureSecurityCenter/Enable": true,
        "Backup/Enable": true,
        "Backup/Policy": "DefaultPolicy",
        "Backup/SchedulePolicy": {
            "scheduleRunFrequency": "Daily",
            "scheduleRunTimes": ["2021-11-20T02:00:00Z"]
        },
        "Backup/RetentionPolicy": {
            "retentionPolicyType": "LongTermRetentionPolicy",
            "dailySchedule": {
                "retentionDuration": {
                    "count": 30,
                    "durationType": "Days"
                }
            }
        },
        "BootDiagnostics/Enable": true,
        "ChangeTrackingAndInventory/Enable": true,
        "GuestConfiguration/Enable": true,
        "LogAnalytics/Enable": true,
        "UpdateManagement/Enable": true,
        "VMInsights/Enable": true
    }'

# Assign to VM
az automanage configuration-profile-assignment create \
    --resource-group rg-vms \
    --vm-name vm-web-01 \
    --configuration-profile "/subscriptions/.../providers/Microsoft.Automanage/configurationProfiles/CustomWebServerProfile"

Profile Configuration Options

{
  "Antimalware": {
    "Enable": true,
    "RealtimeProtectionEnabled": true,
    "ScheduledScanSettings": {
      "isEnabled": true,
      "day": "7",
      "time": "120",
      "scanType": "Quick"
    },
    "Exclusions": {
      "Extensions": ".log;.ldf",
      "Paths": "D:\\Data",
      "Processes": "sqlservr.exe"
    }
  },
  "AzureSecurityCenter": {
    "Enable": true
  },
  "Backup": {
    "Enable": true,
    "Policy": {
      "schedulePolicy": {
        "schedulePolicyType": "SimpleSchedulePolicy",
        "scheduleRunFrequency": "Daily",
        "scheduleRunTimes": ["2021-11-20T02:00:00Z"]
      },
      "retentionPolicy": {
        "retentionPolicyType": "LongTermRetentionPolicy",
        "dailySchedule": {
          "retentionDuration": {
            "count": 30,
            "durationType": "Days"
          }
        },
        "weeklySchedule": {
          "daysOfTheWeek": ["Sunday"],
          "retentionDuration": {
            "count": 12,
            "durationType": "Weeks"
          }
        }
      }
    }
  },
  "ChangeTrackingAndInventory": {
    "Enable": true,
    "fileChangeTrackingEnabled": true,
    "registryChangeTrackingEnabled": true,
    "softwareInventoryEnabled": true
  },
  "GuestConfiguration": {
    "Enable": true,
    "AssignmentType": "ApplyAndAutoCorrect"
  },
  "LogAnalytics": {
    "Enable": true,
    "WorkspaceId": "/subscriptions/.../workspaces/my-workspace"
  },
  "UpdateManagement": {
    "Enable": true,
    "MaintenanceWindow": {
      "duration": "PT2H",
      "startTime": "2021-11-20T03:00:00Z",
      "timeZone": "UTC"
    },
    "Windows": {
      "includedKbNumbers": [],
      "excludedKbNumbers": [],
      "includedUpdateClassifications": "Critical,Security,UpdateRollup"
    }
  },
  "VMInsights": {
    "Enable": true
  }
}

Monitoring Automanage Status

PowerShell Reporting

# Get all Automanage assignments
$assignments = Get-AzAutomanageConfigurationProfileAssignment

# Generate status report
$report = foreach ($assignment in $assignments) {
    $vm = Get-AzVM -ResourceId $assignment.TargetId

    [PSCustomObject]@{
        VMName = $vm.Name
        ResourceGroup = $vm.ResourceGroupName
        Profile = $assignment.ConfigurationProfile.Split('/')[-1]
        Status = $assignment.Status
        LastModified = $assignment.SystemData.LastModifiedAt
    }
}

$report | Format-Table -AutoSize

# Export to CSV
$report | Export-Csv -Path "automanage-status.csv" -NoTypeInformation

Azure Resource Graph

# Query Automanage status
az graph query -q "
    Resources
    | where type == 'microsoft.automanage/configurationprofileassignments'
    | extend vmId = properties.targetId
    | extend status = properties.status
    | extend profile = properties.configurationProfile
    | join kind=leftouter (
        Resources
        | where type == 'microsoft.compute/virtualmachines'
        | project vmId = id, vmName = name, vmRG = resourceGroup
    ) on vmId
    | project vmName, vmRG, status, profile
"

Log Analytics Queries

// Automanage configuration changes
AzureActivity
| where OperationNameValue contains "Microsoft.Automanage"
| project TimeGenerated, Caller, OperationNameValue, ActivityStatusValue
| order by TimeGenerated desc

// VMs without Automanage
Resources
| where type == "microsoft.compute/virtualmachines"
| where tags.Environment == "Production"
| join kind=leftanti (
    Resources
    | where type == "microsoft.automanage/configurationprofileassignments"
    | project vmId = tostring(properties.targetId)
) on $left.id == $right.vmId
| project name, resourceGroup, location

// Update compliance status
UpdateSummary
| where Computer in (
    Resources
    | where type == "microsoft.automanage/configurationprofileassignments"
    | extend vmName = tostring(split(properties.targetId, '/')[-1])
    | project vmName
)
| project Computer, CriticalUpdatesMissing, SecurityUpdatesMissing, TotalUpdatesMissing

Machine Configuration (Guest Configuration)

Create Custom Configuration

# Install required modules
Install-Module -Name GuestConfiguration
Install-Module -Name PSDesiredStateConfiguration

# Create DSC configuration
Configuration SecureWebServer {
    Import-DscResource -ModuleName 'PSDscResources'
    Import-DscResource -ModuleName 'SecurityPolicyDsc'

    Node localhost {
        WindowsFeature IIS {
            Ensure = "Present"
            Name = "Web-Server"
        }

        WindowsFeature ASPNET {
            Ensure = "Present"
            Name = "Web-Asp-Net45"
            DependsOn = "[WindowsFeature]IIS"
        }

        SecurityOption AccountPolicy {
            Name = "AccountPolicy"
            Accounts_Rename_guest_account = "NoGuest"
            Accounts_Rename_administrator_account = "AdminRenamed"
        }

        Registry TLS12Only {
            Ensure = "Present"
            Key = "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server"
            ValueName = "Enabled"
            ValueType = "Dword"
            ValueData = "1"
        }
    }
}

# Compile configuration
SecureWebServer -OutputPath .\SecureWebServer

# Create package
New-GuestConfigurationPackage `
    -Name 'SecureWebServer' `
    -Configuration .\SecureWebServer\localhost.mof `
    -Type AuditAndSet `
    -Force

# Publish to Azure
$package = Publish-GuestConfigurationPackage `
    -Path .\SecureWebServer.zip `
    -ResourceGroupName "rg-guest-config" `
    -StorageAccountName "stguestconfig"

# Create policy
New-GuestConfigurationPolicy `
    -PolicyId (New-Guid) `
    -ContentUri $package.ContentUri `
    -DisplayName "Secure Web Server Configuration" `
    -Description "Ensures web servers meet security requirements" `
    -Path .\policies `
    -Platform Windows `
    -Mode ApplyAndAutoCorrect

Troubleshooting

Common Issues

# Check extension status
Get-AzVMExtension -ResourceGroupName "rg-vms" -VMName "vm-web-01" |
    Where-Object { $_.Publisher -like "*Automanage*" } |
    Select-Object Name, ProvisioningState, StatusMessage

# View detailed logs
$vm = Get-AzVM -ResourceGroupName "rg-vms" -Name "vm-web-01"
Get-AzVMDiagnosticsExtension -ResourceGroupName $vm.ResourceGroupName -VMName $vm.Name

# Reset Automanage
az automanage configuration-profile-assignment delete \
    --resource-group rg-vms \
    --vm-name vm-web-01

az automanage configuration-profile-assignment create \
    --resource-group rg-vms \
    --vm-name vm-web-01 \
    --configuration-profile Production

Azure Automanage transforms VM management from a series of manual tasks into an automated, best-practice-driven process. It’s ideal for organizations that want consistent, secure VM configurations without the operational overhead.

Resources

Michael John Pena

Michael John Pena

Data & AI Director and Microsoft MVP based in Sydney. Writing about Microsoft Fabric, Azure, data engineering, and AI.