How to Set Up Windows Server 2019 with Grafana

Grafana is an open-source analytics and visualization platform that, when combined with a time-series data source, provides powerful dashboards for Windows Server 2019 monitoring. The typical architecture uses Windows Exporter (formerly wmi_exporter) to expose Prometheus-compatible metrics from Windows Server 2019, a Prometheus server to scrape and store those metrics, and Grafana to visualize them. This guide covers the complete setup of this monitoring stack.

Installing Windows Exporter on Windows Server 2019

# Download Windows Exporter 0.25.1
$version = "0.25.1"
$downloadUrl = "https://github.com/prometheus-community/windows_exporter/releases/download/v$version/windows_exporter-$version-amd64.msi"
Invoke-WebRequest -Uri $downloadUrl -OutFile "C:Tempwindows_exporter.msi"

# Install with specific collectors enabled
msiexec /i C:Tempwindows_exporter.msi /quiet `
  ENABLED_COLLECTORS="cpu,cs,logical_disk,memory,net,os,service,system,textfile,process" `
  LISTEN_PORT=9182

# Verify the service started
Get-Service -Name windows_exporter | Select-Object Name, Status, StartType

# Test metrics endpoint
Invoke-WebRequest -Uri "http://localhost:9182/metrics" -UseBasicParsing | Select-Object -ExpandProperty Content | Select-String "windows_cpu"

Configuring Windows Firewall for Windows Exporter

# Allow Prometheus scraping from the Prometheus server
New-NetFirewallRule `
  -Name "Windows-Exporter-Prometheus" `
  -DisplayName "Windows Exporter for Prometheus" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 9182 `
  -RemoteAddress 192.168.1.60 `
  -Action Allow

# Optional: restrict to monitoring VLAN
New-NetFirewallRule `
  -Name "Windows-Exporter-Monitoring-VLAN" `
  -DisplayName "Windows Exporter Monitoring VLAN" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 9182 `
  -RemoteAddress "192.168.10.0/24" `
  -Action Allow

Configuring Prometheus to Scrape Windows Server 2019 Metrics

On the Prometheus server (Linux or Windows), add the Windows Server 2019 targets to the Prometheus configuration file prometheus.yml:

global:
  scrape_interval: 30s
  evaluation_interval: 30s

scrape_configs:
  - job_name: 'windows_servers_2019'
    scrape_interval: 30s
    scrape_timeout: 20s
    static_configs:
      - targets:
          - '192.168.1.200:9182'
          - '192.168.1.201:9182'
          - '192.168.1.202:9182'
        labels:
          environment: 'production'
          os: 'windows2019'
          datacenter: 'dc1'
    relabel_configs:
      - source_labels: [__address__]
        regex: '([^:]+):.*'
        target_label: instance
        replacement: '$1'
# Reload Prometheus configuration
curl -X POST http://localhost:9090/-/reload

# Verify targets are up
curl http://localhost:9090/api/v1/targets | python3 -m json.tool | grep -A5 "windows_servers"

Installing Grafana and Adding Prometheus Data Source

# On Linux Grafana server
sudo apt-get install -y apt-transport-https software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
sudo apt-get update && sudo apt-get install -y grafana
sudo systemctl enable grafana-server && sudo systemctl start grafana-server

# Configure Prometheus as a data source via API
curl -X POST http://admin:admin@localhost:3000/api/datasources 
  -H "Content-Type: application/json" 
  -d '{
    "name": "Prometheus-WS2019",
    "type": "prometheus",
    "url": "http://localhost:9090",
    "access": "proxy",
    "isDefault": true
  }'

Importing the Windows Server Dashboard

Import the community Windows Server dashboard (dashboard ID 14694 on Grafana.com) via the API:

# Import dashboard 14694 (Windows Node - wmi exporter)
curl -X POST http://admin:admin@localhost:3000/api/dashboards/import 
  -H "Content-Type: application/json" 
  -d '{
    "dashboard": {"id": null, "title": "Windows Server 2019 Overview"},
    "folderId": 0,
    "overwrite": false,
    "inputs": [{
      "name": "DS_PROMETHEUS",
      "type": "datasource",
      "pluginId": "prometheus",
      "value": "Prometheus-WS2019"
    }]
  }'

Creating Custom Grafana Panels with PromQL

Build custom panels with Prometheus Query Language (PromQL) to visualize Windows Server 2019 metrics:

# CPU Usage % per server
100 - (avg by (instance) (rate(windows_cpu_time_total{mode="idle"}[5m])) * 100)

# Memory Used %
100 - ((windows_os_physical_memory_free_bytes / windows_cs_physical_memory_bytes) * 100)

# Disk Read IOPS
rate(windows_logical_disk_reads_total{volume=~"C:|D:"}[5m])

# Disk Write IOPS
rate(windows_logical_disk_writes_total{volume=~"C:|D:"}[5m])

# Network Throughput (bytes/sec received)
rate(windows_net_bytes_received_total{nic!~"isatap|VPN|Loopback"}[5m])

# Service state (1 = running, 0 = stopped)
windows_service_state{state="running",name=~"DNS|DHCP|W32Time"}

# System uptime in hours
(time() - windows_system_system_up_time) / 3600

Setting Up Grafana Alerting for Windows Server 2019

# Create alert rule via Grafana API
curl -X POST http://admin:admin@localhost:3000/api/v1/provisioning/alert-rules 
  -H "Content-Type: application/json" 
  -d '{
    "title": "Windows Server High CPU",
    "condition": "C",
    "data": [{
      "refId": "A",
      "queryType": "",
      "datasourceUid": "prometheus-ws2019",
      "model": {
        "expr": "100 - (avg by (instance) (rate(windows_cpu_time_total{mode="idle"}[5m])) * 100)",
        "intervalMs": 30000,
        "maxDataPoints": 43200
      }
    }],
    "noDataState": "NoData",
    "execErrState": "Alerting",
    "for": "5m",
    "annotations": {"summary": "CPU usage above 90% for 5 minutes"},
    "labels": {"severity": "critical"},
    "isPaused": false
  }'

After creating dashboards, organize them into folders by environment (Production, Staging, Dev) and use Grafana’s Team and permission system to restrict access. Export dashboards as JSON and store them in version control so infrastructure-as-code practices apply to your monitoring configuration as well as your server configuration.