๐ฅ️ How to Create an Automatic Server Monitoring Script Using PowerShell in 2026
Monitor CPU, RAM, Disk Space and Windows Services with Automatic Email Alerts | ITSolution4U๐ Introduction
Server monitoring is an essential IT administration task. Windows Servers host business applications, databases, file servers, backup systems, and other critical services. If a server runs out of disk space, experiences high CPU usage, or stops an important service, it can affect business operations.
Instead of checking every server manually, IT administrators can create a PowerShell monitoring script that automatically checks server health and sends email alerts when defined thresholds are exceeded.
In this tutorial, you will learn how to:
๐ฅ️ Monitor CPU usage.
๐ง Monitor RAM utilization.
๐พ Check free disk space.
⚙️ Verify important Windows services.
๐ง Send automatic email alerts.
⏰ Run monitoring automatically using Windows Task Scheduler.
๐ Maintain a monitoring log.
Environment: Windows Server 2016, 2019, 2022, or 2025 with Windows PowerShell 5.1. Test on your server version before production deployment.
๐งฐ 1. Prerequisites
Before creating the script, ensure you have:
Administrator access to the Windows Server.
Windows PowerShell 5.1.
An approved SMTP server or internal mail relay.
Permission to send monitoring emails.
Windows Task Scheduler access.
A dedicated folder for scripts and logs.
Create the monitoring folder by opening PowerShell as Administrator and running:
New-Item -Path "C:\ServerMonitor" -ItemType Directory -Force๐ 2. Create the PowerShell Monitoring Script
Create a file named ServerMonitor.ps1 in C:\ServerMonitor.
Copy the following script into the file and update the configuration values before using it.
# ITSolution4U - Windows Server Monitoring Script
# PowerShell 5.1
$ErrorActionPreference = "Stop"
# -------- CONFIGURATION --------
$CpuThreshold = 85
$MemoryThreshold = 85
$DiskThreshold = 15
$AlertCooldownMin = 30
# Update these service names for your server.
$ServicesToCheck = @(
"LanmanServer",
"W32Time"
)
$SmtpServer = "smtp.yourcompany.com"
$SmtpPort = 587
$MailFrom = "server-alerts@yourcompany.com"
$MailTo = "it-admin@yourcompany.com"
$CredentialFile = "C:\ServerMonitor\smtp-credential.xml"
$LogFile = "C:\ServerMonitor\monitor.log"
$StateFile = "C:\ServerMonitor\last-alert.txt"
# -------- LOGGING --------
function Write-Log {
param([string]$Message)
$Line = "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - $Message"
Add-Content -Path $LogFile -Value $Line
}
$Alerts = @()
try {
# -------- CPU MONITORING --------
$CpuValues = Get-CimInstance Win32_Processor |
Select-Object -ExpandProperty LoadPercentage
$CpuUsage = [math]::Round(
($CpuValues | Measure-Object -Average).Average, 1
)
if ($CpuUsage -ge $CpuThreshold) {
$Alerts += "High CPU usage: $CpuUsage%"
}
# -------- MEMORY MONITORING --------
$OS = Get-CimInstance Win32_OperatingSystem
$TotalMemory = [double]$OS.TotalVisibleMemorySize
$FreeMemory = [double]$OS.FreePhysicalMemory
if ($TotalMemory -gt 0) {
$MemoryUsage = [math]::Round(
(($TotalMemory - $FreeMemory) / $TotalMemory) * 100, 1
)
if ($MemoryUsage -ge $MemoryThreshold) {
$Alerts += "High memory usage: $MemoryUsage%"
}
}
# -------- DISK MONITORING --------
$Disks = Get-CimInstance Win32_LogicalDisk `
-Filter "DriveType=3"
foreach ($Disk in $Disks) {
if ($Disk.Size -gt 0) {
$FreePercent = [math]::Round(
($Disk.FreeSpace / $Disk.Size) * 100, 1
)
if ($FreePercent -lt $DiskThreshold) {
$Alerts += "Low disk space on $($Disk.DeviceID): $FreePercent% free"
}
}
}
# -------- SERVICE MONITORING --------
foreach ($ServiceName in $ServicesToCheck) {
$Service = Get-Service -Name $ServiceName `
-ErrorAction SilentlyContinue
if ($null -eq $Service) {
$Alerts += "Required service not found: $ServiceName"
}
elseif ($Service.Status -ne "Running") {
$Alerts += "Service is not running: $ServiceName"
}
}
Write-Log "Check completed. CPU=$CpuUsage%; Memory=$MemoryUsage%"
# -------- EMAIL ALERT WITH COOLDOWN --------
if ($Alerts.Count -gt 0) {
$SendAlert = $true
if (Test-Path $StateFile) {
$LastAlertText = Get-Content $StateFile -Raw
try {
$LastAlert = [datetime]::Parse($LastAlertText)
if (((Get-Date) - $LastAlert).TotalMinutes `
-lt $AlertCooldownMin) {
$SendAlert = $false
}
}
catch {
Write-Log "Could not read alert cooldown state."
}
}
if ($SendAlert) {
if (-not (Test-Path $CredentialFile)) {
throw "SMTP credential file is missing."
}
$Credential = Import-Clixml -Path $CredentialFile
$Subject = "Server Health Alert - $env:COMPUTERNAME"
$Body = @"
Server Monitoring Alert
Server: $env:COMPUTERNAME
Time: $(Get-Date)
Issues detected:
$($Alerts -join "`r`n")
Please investigate the server health and take appropriate action.
"@
$Mail = New-Object System.Net.Mail.MailMessage
$Mail.From = $MailFrom
$Mail.To.Add($MailTo)
$Mail.Subject = $Subject
$Mail.Body = $Body
$SMTP = New-Object System.Net.Mail.SmtpClient(
$SmtpServer, $SmtpPort
)
$SMTP.EnableSsl = $true
$SMTP.Credentials = $Credential.GetNetworkCredential()
try {
$SMTP.Send($Mail)
Set-Content -Path $StateFile `
-Value (Get-Date).ToString("o")
Write-Log "Email alert sent successfully."
}
finally {
$Mail.Dispose()
$SMTP.Dispose()
}
}
else {
Write-Log "Alert suppressed by cooldown period."
}
}
else {
Write-Log "No threshold alerts detected."
}
}
catch {
Write-Log "ERROR: $($_.Exception.Message)"
throw
}How does the script work?
| Component | Purpose |
|---|---|
| CPU monitoring | Alerts at or above 85% usage |
| RAM monitoring | Alerts at or above 85% usage |
| Disk monitoring | Alerts when free space falls below 15% |
| Service monitoring | Checks configured Windows services |
| SMTP email | Sends alerts to the IT administrator |
| Cooldown | Limits repeated alert emails to one per 30 minutes |
| Log file | Records checks, alerts, and errors |
Note: The cooldown is global, so one alert can temporarily suppress another alert during the same period. This starter script does not send recovery notifications and does not replace a dedicated monitoring platform.
๐ง 3. Configure SMTP Credentials Securely
Do not put an email password directly into the script.
For an organization with an approved SMTP server, update the SMTP settings to match its requirements. If authentication is required, run this one-time command under the same Windows account that will run the scheduled task:
Get-Credential |
Export-Clixml -Path "C:\ServerMonitor\smtp-credential.xml"Enter the authorized SMTP username and password in the credential prompt.
Important security considerations:
Protect the credential file with Windows NTFS permissions.
The exported credential is normally protected using Windows DPAPI and is tied to the exporting user and computer.
Run the scheduled task under that same account.
If your mail provider requires OAuth or does not support basic SMTP authentication, use an approved relay or supported authentication method instead.
Confirm that the SMTP port and outbound firewall rules are permitted.
๐งช 4. Test the Script Manually
Open PowerShell under the account that will run the monitoring job and execute:
Set-Location "C:\ServerMonitor"
.\ServerMonitor.ps1Review the monitoring log:
Get-Content "C:\ServerMonitor\monitor.log" -Tail 30Test with appropriate thresholds in a non-production environment, or use a controlled test that does not interrupt business services. Verify that the script records results and that email delivery works before scheduling it.
⏰ 5. Schedule Automatic Monitoring
Windows Task Scheduler can run the script at a recurring interval.
Open Task Scheduler.
Select Create Task.
Enter the name
ITSolution4U Server Monitoring.Configure the task to run under the account that has the required permissions and SMTP credential access.
Under Triggers, create a daily trigger and set it to repeat every 5 minutes for an appropriate duration.
Under Actions, choose Start a program.
Enter the program:
powershell.exeEnter the arguments:
-NoProfile -NonInteractive -File "C:\ServerMonitor\ServerMonitor.ps1"Save the task and run it manually once to verify the result.
Check Last Run Result, Task Scheduler history, and the monitoring log.
Avoid overlapping task executions. Configure the task to avoid starting a new instance while a previous instance is still running.
๐ก️ 6. Recommended Monitoring Thresholds
These are starting points, not universal standards. Adjust them according to the workload and baseline of each server.
| Metric | Example threshold | Recommended action |
|---|---|---|
| CPU utilization | 85% or higher | Investigate sustained load |
| RAM utilization | 85% or higher | Review memory pressure |
| Free disk space | Below 15% | Review growth and capacity |
| Critical service | Not running | Check service and dependencies |
| Email delivery | Failed | Review SMTP configuration and logs |
For critical production servers, consider separate warning and critical thresholds, per-alert cooldowns, recovery notifications, and an independent monitoring channel.
๐ 7. Further Improvements
After validating the basic script, you can extend it with:
๐ Daily server health reports in CSV or HTML.
๐ฅ️ Monitoring multiple Windows servers.
๐พ Backup job and backup repository checks.
๐ Network connectivity and latency checks.
๐ Microsoft Teams or other approved notification integrations.
๐ Weekly or monthly health summaries.
๐ CPU, RAM, disk, and service status history.
๐ Centralized logging and role-based access controls.
For larger environments, compare this custom script with established monitoring platforms such as Zabbix, PRTG, or Prometheus-based solutions. A script is useful for simple automation, but a monitoring platform generally offers stronger dashboards, history, escalation, and centralized management.
❓ Frequently Asked Questions
Can this script run without a logged-in administrator?
Yes, when Task Scheduler is configured with a suitable service or user account and the necessary permissions.
Will it send an email every five minutes?
No. The example uses a 30-minute global cooldown when alerts are detected. It can still send repeated notifications if an issue persists beyond the cooldown.
Can I monitor a Linux server?
This particular script is designed for Windows Server. Linux monitoring would require a different script or monitoring agent.
Does it monitor antivirus, backups, or event logs?
Not in its current form. Those checks can be added separately after validating the core monitoring workflow.
✅ Conclusion
A PowerShell server monitoring script can automate basic checks for CPU usage, memory utilization, disk capacity, and Windows services. By combining the script with SMTP email alerts and Windows Task Scheduler, IT administrators can detect selected server issues sooner and reduce repetitive manual checks.
Always test the script, secure its credentials, and verify alert delivery before using it in a production environment.
๐ ITSolution4U — Learn | Solve | Grow
๐ Website: https://www.itsolution4u.in
๐ง Email: info@itsolution4u.in
๐ Contact: +91 9824974641
๐ฑ Social media: @ITSolution4U
Hashtags:
#PowerShell #ServerMonitoring #WindowsServer #ITAutomation #SystemAdministrator #ServerManagement #EmailAlerts #ITSolution4U
