Introduction

In many enterprise environments, Windows services are critical to application availability. While Windows provides basic service recovery (restart on failure), it doesn’t tell you when something broke or what server needs attention.


This solution combines:

A service monitoring PowerShell script

A Teams adaptive card for rich notifications

A one-time setup script to configure Windows service recovery actions


Together, they provide automated detection, recovery, and alerting when key services stop.


Component Purpose 

Service-Monitor.ps1 

Actively checks service state and sends alerts 


adaptive_card.json 

Defines the Teams alert layout 


setup-servicemonitoring.ps1 

Configures Windows service recovery options 


Each piece is intentionally separated to keep the solution modular and easy to maintain.


1. Service-Monitor.ps1 – Active Service Monitoring & Alerting

This script is responsible for:


Checking whether specific Windows services are running

Detecting stopped or failed services

Sending a structured alert to Microsoft Teams


Key Configuration Section

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 
$WebhookUrl "<YOUR-TEAMS-WEBHOOK-URL>" 
$services = @( 
    "AxInstSV" #service used to test
)
$jsonPath = Join-Path $PSScriptRoot "adaptive_card.json"



What this does:


  • Forces TLS 1.2 (required for modern HTTPS endpoints)
  • Defines the Teams webhook endpoint (replace with your own)
  • Lists services to monitor
  • Loads the adaptive card JSON template from disk


Adaptive Card Loading & Validation

if (-not (Test-Path $jsonPath)) { 
  Write-Error "adaptive_card.json not found" 
  exit 
} 
$jsonTemplate = Get-Content -Path $jsonPath -Raw

This ensures the alert template exists before monitoring begins, preventing silent failures.


Service State Checking Loop

The script iterates through each configured service:

foreach ($serviceName in $services) { 
  Write-Host "Checking $serviceName..." -NoNewline 
}

Inside the loop (not shown in the excerpt), the script:


  • Queries the service status
  • Detects non-running states
  • Injects real values (service name, server name, state)
  • Sends the populated adaptive card to Teams


2. adaptive_card.json – Teams Alert Template

This JSON file defines how the alert appears in Teams.


Alert Header

"type""TextBlock""text""CRITICAL ALERT: ${service} Service Stopped""weight""Bolder""size""Large""color""Attention" 
} 

This creates a bold, red, highly visible alert header


Contextual Information

"type""FactSet""facts": [ 
    { "title""Server Name""value""${serverName}" }, 
    { "title""Service""value""${service}" } 
  ] 
}

 This provides immediate operational context so responders know:


  • Which server is impacted
  • Which service requires attention


Human-Readable Description

"type""TextBlock""text""The ${service} service has failed and is in a ${state} state. Please remote onto ${serverName} to investigate.""wrap"true 
}

This reduces guesswork and shortens incident response time.


3. setup-servicemonitoring.ps1 – Service Recovery Configuration

This is a one-time setup script that configures Windows service recovery actions.


Services to Configure

$Services = @( 
  'Spooler''W32Time' 
  #add/remove services as required.
)

Only services explicitly listed will be modified.


Recovery Behaviour Settings

$RestartDelayMs = 60000 
$ResetAfterSeconds = 86400
  • Restart service after 60 seconds
  • Reset failure counter after 24 hours


Recovery Action Command

$ProgramPath = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' 
$ProgramParameters = '-executionpolicy bypass -windowstyle hidden -file "C:\Scripts\ServiceMonitoring\Service-Monitor.ps1"'

On service failure, Windows will:


  1. Attempt a service restart
  2. If failures persist, execute the monitoring script silently
  3. Trigger Teams notification


Applying Recovery Options 

The function Set-ServiceRecoveryOptions uses sc.exe to configure: 

  • Failure actions
  • Restart behaviour
  • Command execution on failure


sc.exe failure "$ServiceName" reset= $ResetAfterSeconds actions= $actions command"$fullRunCommand"

This directly modifies service configuration at the OS level.


Elevated Permissions Check

if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { 
  Write-Error "Please run this script as Administrator." 
}

Service recovery settings require elevation, and this check prevents partial execution.


How Everything Fits Together

  1. Setup script configures Windows to react to service failures
  2. Windows Service Control Manager detects a failure
  3. Service recovery restarts and/or runs the monitor script
  4. Monitor script checks service state
  5. Adaptive card sends a rich Teams alert

This creates a self-healing, observable service monitoring pattern.


Deployment Tips

  • Store all files in the same directory
  • Test scripts manually before enabling recovery
  • Start with non-production environments
  • Document which services are monitored


Conclusion

This approach bridges the gap between automatic recovery and human visibility. By combining native Windows service recovery with PowerShell and Teams adaptive cards, you get faster detection, clearer alerts, and reduced mean time to resolution.


It’s lightweight, transparent, and easily extensible—ideal for application support and SRE-style operations.


All the files for this can be found on my github, here