How to Use Azure Monitor with Windows Server 2022

Azure Monitor provides a comprehensive solution for collecting, analyzing, and acting on telemetry from Windows Server 2022 environments — whether those servers run on-premises, in Azure, or in other clouds. This guide walks through the full setup of Azure Monitor for Windows Server 2022, from agent installation through alerting and automated remediation.

Azure Monitor Agent vs Log Analytics Agent (MMA)

For many years the Microsoft Monitoring Agent (MMA), also called the Log Analytics Agent, was the primary method for connecting Windows servers to Azure Monitor and Log Analytics workspaces. Microsoft has deprecated the MMA and its companion Dependency Agent in favor of the Azure Monitor Agent (AMA). AMA uses Data Collection Rules (DCR) to precisely define what data is collected and where it is sent, replacing the workspace-level configuration model of the MMA.

Key differences between the agents are important to understand before deployment. The MMA collects data at the workspace level — any Windows Server connected to a workspace sends the event channels and performance counters configured on the workspace itself. The AMA inverts this: rules are defined centrally in Azure as Data Collection Rule resources and then associated with specific machines or groups of machines. This gives per-machine granularity and eliminates the need to over-collect data. AMA also supports sending to multiple workspaces from a single rule, supports data collection endpoints for private link scenarios, and offers better performance at scale.

If you are running Windows Server 2022 in Azure you can install AMA directly via the Azure portal VM extension. For on-premises or multi-cloud servers you must first connect the server to Azure using Azure Arc.

Connecting Windows Server 2022 to Azure via Azure Arc

Azure Arc-enabled servers extend Azure management plane capabilities to non-Azure machines. Installing the Arc Connected Machine Agent on Windows Server 2022 registers the server as an Azure resource, enabling AMA installation, policy assignment, and access to Azure services such as Defender for Cloud, Update Manager, and Change Tracking.

To onboard a single Windows Server 2022 machine interactively, download the installation script from the Azure portal under Azure Arc > Servers > Add. Choose the single server method, select your subscription, resource group, region, and operating system. The portal generates a PowerShell script. Run it on the server in an elevated PowerShell session:


# Download and run the Arc onboarding script (example)
# The script generated by the portal includes your specific tenant, subscription, and resource group

$env:SUBSCRIPTION_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$env:RESOURCE_GROUP = "rg-monitoring"
$env:TENANT_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$env:LOCATION = "eastus"
$env:AUTH_TYPE = "token"
$env:CORRELATION_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$env:CLOUD = "AzureCloud"

Invoke-WebRequest -Uri "https://aka.ms/azcmagent-windows" -OutFile "$env:TEMPinstall_windows_azcmagent.ps1"
& "$env:TEMPinstall_windows_azcmagent.ps1"

# Connect the agent to Azure
& "$env:ProgramFilesAzureConnectedMachineAgentazcmagent.exe" connect `
  --subscription-id $env:SUBSCRIPTION_ID `
  --resource-group $env:RESOURCE_GROUP `
  --tenant-id $env:TENANT_ID `
  --location $env:LOCATION `
  --cloud $env:CLOUD

After the script completes, verify the connection status:


& "$env:ProgramFilesAzureConnectedMachineAgentazcmagent.exe" show

The output shows the agent status, the Azure resource ID of the machine, and the connected Azure services. Once the server shows as Connected in the portal, you can install extensions including AMA.

Installing Azure Monitor Agent via Azure Policy

For at-scale deployments, Azure Policy provides the most operationally efficient approach to AMA installation. Microsoft publishes built-in policy initiatives specifically for this purpose. The initiative named “Enable Azure Monitor for VMs” (or its equivalent for Arc-enabled servers) deploys AMA and the Dependency Agent and associates a default Data Collection Rule.

To assign the policy initiative from the Azure CLI:


# List available built-in AMA policy initiatives
az policy set-definition list --query "[?contains(displayName, 'Azure Monitor')].{Name:displayName, ID:id}" -o table

# Assign the initiative to a resource group
az policy assignment create 
  --name "enable-azure-monitor-vms" 
  --display-name "Enable Azure Monitor for VMs" 
  --scope "/subscriptions//resourceGroups/rg-monitoring" 
  --policy-set-definition "/providers/Microsoft.Authorization/policySetDefinitions/" 
  --assign-identity 
  --location eastus 
  --mi-user-assigned "/subscriptions//resourceGroups/rg-monitoring/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ama-identity"

Policy assignments with deployIfNotExists effects require a managed identity with Contributor rights on the scope so the policy engine can perform remediation deployments. After assignment, create a remediation task to deploy AMA to existing non-compliant machines immediately rather than waiting for the next evaluation cycle.

Configuring Data Collection Rules for Windows Server

A Data Collection Rule (DCR) defines three things: the data sources to collect (Windows Event Logs, Performance Counters, Syslog, IIS logs, custom text logs), the destinations to send data to (Log Analytics workspace, Azure Monitor Metrics, Azure Data Explorer), and a transformation query that can filter or reshape data in the pipeline before storage. AMA reads DCRs associated with the machine and begins collecting according to those rules.

Create a DCR using the Azure portal under Monitor > Data Collection Rules > Create, or via ARM template. The following is an ARM template fragment for a DCR that collects Windows Event Logs from the Application, System, and Security channels plus key performance counters:


{
  "type": "Microsoft.Insights/dataCollectionRules",
  "apiVersion": "2022-06-01",
  "name": "dcr-windows-server-2022",
  "location": "eastus",
  "properties": {
    "dataSources": {
      "windowsEventLogs": [
        {
          "name": "eventLogsDataSource",
          "streams": ["Microsoft-Event"],
          "xPathQueries": [
            "Application!*[System[(Level=1 or Level=2 or Level=3)]]",
            "System!*[System[(Level=1 or Level=2 or Level=3)]]",
            "Security!*[System[(EventID=4624 or EventID=4625 or EventID=4648 or EventID=4720 or EventID=4726)]]"
          ]
        }
      ],
      "performanceCounters": [
        {
          "name": "perfCountersDataSource",
          "streams": ["Microsoft-Perf"],
          "samplingFrequencyInSeconds": 60,
          "counterSpecifiers": [
            "\Processor(_Total)\% Processor Time",
            "\Memory\Available MBytes",
            "\Memory\% Committed Bytes In Use",
            "\LogicalDisk(_Total)\% Disk Time",
            "\LogicalDisk(_Total)\Disk Reads/sec",
            "\LogicalDisk(_Total)\Disk Writes/sec",
            "\LogicalDisk(_Total)\% Free Space",
            "\Network Interface(*)\Bytes Total/sec",
            "\System\Processor Queue Length"
          ]
        }
      ]
    },
    "destinations": {
      "logAnalytics": [
        {
          "name": "lawDestination",
          "workspaceResourceId": "/subscriptions//resourceGroups/rg-monitoring/providers/Microsoft.OperationalInsights/workspaces/law-production"
        }
      ]
    },
    "dataFlows": [
      {
        "streams": ["Microsoft-Event"],
        "destinations": ["lawDestination"],
        "outputStream": "Microsoft-Event"
      },
      {
        "streams": ["Microsoft-Perf"],
        "destinations": ["lawDestination"],
        "outputStream": "Microsoft-Perf"
      }
    ]
  }
}

Deploy this template with the Azure CLI:


az deployment group create 
  --resource-group rg-monitoring 
  --template-file dcr-windows.json

# Associate the DCR with a specific machine (Arc-enabled server)
az monitor data-collection rule association create 
  --name "assoc-win2022-server01" 
  --resource "/subscriptions//resourceGroups/rg-servers/providers/Microsoft.HybridCompute/machines/WinServer01" 
  --rule-id "/subscriptions//resourceGroups/rg-monitoring/providers/Microsoft.Insights/dataCollectionRules/dcr-windows-server-2022"

VM Insights for Windows Server 2022

VM Insights provides curated workbooks and monitoring views purpose-built for virtual machines and physical servers. It relies on AMA and the Dependency Agent. The Performance tab displays CPU, memory, disk, and network metrics for individual machines or aggregated across groups, with baseline comparisons. The Map tab uses the Dependency Agent to discover and visualize TCP connections between the server and other endpoints, helping map service dependencies automatically without manual documentation.

Enable VM Insights from the portal by navigating to Monitor > Virtual Machines > and selecting the machine, then clicking Enable. Alternatively, use the Azure CLI to confirm the Dependency Agent extension is installed:


# Check extensions on an Arc-enabled server
az connectedmachine extension list 
  --resource-group rg-servers 
  --machine-name WinServer01 
  --query "[].{Name:name, Type:typePropertiesType, Status:provisioningState}" -o table

# Install Dependency Agent extension on Arc-enabled server
az connectedmachine extension create 
  --resource-group rg-servers 
  --machine-name WinServer01 
  --name DependencyAgentWindows 
  --type DependencyAgentWindows 
  --publisher Microsoft.Azure.Monitoring.DependencyAgent 
  --settings '{"enableAMA": true}'

Azure Monitor Alerts Based on Windows Metrics

Azure Monitor supports metric alerts (near real-time, based on numeric time-series data) and log search alerts (based on KQL queries against a Log Analytics workspace). For Windows Server performance metrics collected via AMA into Azure Monitor Metrics, metric alerts are the lowest-latency option. For event-log based conditions such as detecting failed logon spikes, log search alerts are appropriate.

Create a metric alert for CPU threshold using PowerShell:


# Install Az.Monitor if needed
Install-Module -Name Az.Monitor -Force

Connect-AzAccount

# Create an action group for email notification
$emailReceiver = New-AzActionGroupReceiver -Name "OpsTeam" -EmailReceiver -EmailAddress "[email protected]"
$actionGroup = Set-AzActionGroup `
  -ResourceGroupName "rg-monitoring" `
  -Name "ag-windows-ops" `
  -ShortName "WinOps" `
  -Receiver $emailReceiver

# Create a metric alert rule: CPU > 90% for 5 minutes
$condition = New-AzMetricAlertRuleV2Criteria `
  -MetricName "Processor% Processor Time" `
  -MetricNamespace "Azure.VM.Windows.GuestMetrics" `
  -Operator GreaterThan `
  -Threshold 90 `
  -TimeAggregation Average

Add-AzMetricAlertRuleV2 `
  -ResourceGroupName "rg-servers" `
  -Name "alert-cpu-winserver01-high" `
  -TargetResourceId "/subscriptions//resourceGroups/rg-servers/providers/Microsoft.HybridCompute/machines/WinServer01" `
  -TargetResourceType "Microsoft.HybridCompute/machines" `
  -TargetResourceRegion "eastus" `
  -Condition $condition `
  -ActionGroupId $actionGroup.Id `
  -WindowSize ([TimeSpan]::FromMinutes(5)) `
  -Frequency ([TimeSpan]::FromMinutes(1)) `
  -Severity 2 `
  -Description "CPU usage exceeded 90% for 5 minutes"

Log Analytics Workspace KQL Queries for Windows Server

Once Windows Event Logs and Performance Counters flow into a Log Analytics workspace, the KQL (Kusto Query Language) query editor allows powerful ad-hoc and saved analysis. The primary tables for Windows Server data are Event (Windows event logs), Perf (performance counters), SecurityEvent (Security channel events when using Sentinel or the legacy MMA), and Heartbeat (agent connectivity).

Check which servers have not reported a heartbeat in the last 15 minutes:


Heartbeat
| where TimeGenerated > ago(24h)
| summarize LastHeartbeat = max(TimeGenerated) by Computer, OSType, Version
| where LastHeartbeat < ago(15m)
| project Computer, OSType, Version, LastHeartbeat
| order by LastHeartbeat asc

Query average CPU usage by computer over the last hour:


Perf
| where TimeGenerated > ago(1h)
| where ObjectName == "Processor" and CounterName == "% Processor Time" and InstanceName == "_Total"
| summarize AvgCPU = avg(CounterValue), MaxCPU = max(CounterValue) by Computer, bin(TimeGenerated, 5m)
| order by Computer asc, TimeGenerated asc

Detect failed logon attempts (Event ID 4625):


Event
| where TimeGenerated > ago(24h)
| where EventID == 4625
| extend AccountName = extract(@"Account Name:s+(S+)", 1, RenderedDescription)
| extend WorkstationName = extract(@"Workstation Name:s+(S+)", 1, RenderedDescription)
| extend IpAddress = extract(@"Source Network Address:s+(S+)", 1, RenderedDescription)
| summarize FailedAttempts = count() by Computer, AccountName, IpAddress, bin(TimeGenerated, 1h)
| where FailedAttempts > 5
| order by FailedAttempts desc

Find the top 10 Windows Error events by source in the last 24 hours:


Event
| where TimeGenerated > ago(24h)
| where EventLevelName == "Error"
| summarize Count = count() by Source, EventID, Computer
| top 10 by Count desc
| project Source, EventID, Computer, Count

Integrating Azure Monitor with Azure Automation for Remediation

Azure Automation runbooks can be triggered automatically from Azure Monitor alert action groups. This enables self-healing scenarios such as automatically restarting a failed Windows service when a specific Event ID is detected, or clearing disk space when a threshold alert fires.

Create an Automation account and a runbook that restarts a Windows service on a target server via Hybrid Runbook Worker:


# In Azure Automation, create a PowerShell runbook named Restart-WindowsService
param (
    [Parameter(Mandatory=$true)]
    [string]$ComputerName,

    [Parameter(Mandatory=$true)]
    [string]$ServiceName
)

$service = Get-Service -ComputerName $ComputerName -Name $ServiceName -ErrorAction Stop

if ($service.Status -ne "Running") {
    Write-Output "Service $ServiceName on $ComputerName is $($service.Status). Attempting restart..."
    Restart-Service -InputObject (Get-Service -ComputerName $ComputerName -Name $ServiceName)
    Start-Sleep -Seconds 10
    $service.Refresh()
    Write-Output "Service status after restart: $($service.Status)"
} else {
    Write-Output "Service $ServiceName on $ComputerName is already running."
}

Add an Automation Runbook action to an alert action group via the portal by selecting Automation Runbook as the action type, specifying the runbook name, and enabling the Hybrid Worker toggle so the runbook executes on the local server rather than in Azure cloud sandbox. This completes a fully automated monitoring-to-remediation pipeline for Windows Server 2022 using native Azure tooling.