├── LICENSE ├── README.md ├── WinServ-Status.ps1 └── servers-example.txt /LICENSE: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 Mike Galvin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Windows Server Status Monitor (WSSM) 2 | 3 | ## PowerShell based Windows Server monitor 4 | 5 | For full instructions and documentation, [visit my blog post](https://gal.vin/posts/windows-server-status/) 6 | 7 | Please consider donating to support my work: 8 | 9 | * You can support me with a one-time payment [using PayPal](https://www.paypal.me/digressive) 10 | 11 | Windows Server Status Monitor can also be downloaded from: 12 | 13 | * [The PowerShell Gallery](https://www.powershellgallery.com/packages/WinServ-Status) 14 | 15 | Please report any problems via the ‘issues’ tab on GitHub. 16 | 17 | -Mike 18 | 19 | ## Features and Requirements 20 | 21 | * The utility will display the server name, uptime, CPU, memory and storage information, online status. 22 | * The utility can be configured with a customisable alerts for the CPU, memory and storage. 23 | * The utility can display the results as either a CSV file or a HTML file. 24 | * The utility can be configured to monitor continuously, or run once. 25 | * The utility can be configured to e-mail the results. 26 | * This utility has been tested running on Windows 10 and Windows Server 2016, monitoring PCs and Servers running Windows 10, Windows Server 2016, Windows Server 2012 R2, and Windows Server 2008 R2. 27 | * The utility must be run as a user with administrator-level privileges to the systems it is monitoring. 28 | 29 | ## Generating A Password File For SMTP Authentication 30 | 31 | The password used for SMTP server authentication must be in an encrypted text file. To generate the password file, run the following command in PowerShell, on the computer that is going to run the script and logged in with the user that will be running the script. When you run the command you will be prompted for a username and password. Enter the username and password you want to use to authenticate to your SMTP server. 32 | 33 | Please note: This is only required if you need to authenticate to the SMTP server when send the log via e-mail. 34 | 35 | ``` powershell 36 | $creds = Get-Credential 37 | $creds.Password | ConvertFrom-SecureString | Set-Content c:\scripts\ps-script-pwd.txt 38 | ``` 39 | 40 | After running the commands, you will have a text file containing the encrypted password. When configuring the -Pwd switch enter the path and file name of this file. 41 | 42 | ## Configuration 43 | 44 | Here’s a list of all the command line switches and example configurations. 45 | 46 | | Command Line Switch | Description | Example | 47 | | ------------------- | ----------- | ------- | 48 | | -List | The path to a TXT file containing the NetBIOS names of the servers you wish to check. | [path\]servers.txt | 49 | | -O | The path where the report file will be output to. | [path\] | 50 | | -DiskAlert | The percentage of disk usage that should cause the disk space alert to be raised. | [number] | 51 | | -CpuAlert | The percentage of CPU usage that should cause the CPU alert to be raised. | [number] | 52 | | -MemAlert | The percentage of memory usage that should cause the memory alert to be raised. | [number] | 53 | | -Refresh | The number of seconds that she script should wait before running again. The minimum is 300 seconds (5 minutes) and the maximum is 28800 (8 hours). If not configured the script will run once and then exit. | [number] | 54 | | -Light | Configure the HTML results file to have a light theme. | N/A | 55 | | -csv | Export a CSV file, instead of a HTML file. | [path\]| 56 | | -Subject | Specify a subject line. If you leave this blank the default subject will be used | "'[Server: Notification]'" | 57 | | -SendTo | The e-mail address the log should be sent to. For multiple address, separate with a comma. | [example@contoso.com] | 58 | | -From | The e-mail address the log should be sent from. | [example@contoso.com] | 59 | | -Smtp | The DNS name or IP address of the SMTP server. | [smtp server address] | 60 | | -User | The user account to authenticate to the SMTP server. | [example@contoso.com] | 61 | | -Pwd | The txt file containing the encrypted password for SMTP authentication. | [path\]ps-script-pwd.txt | 62 | | -UseSsl | Configures the utility to connect to the SMTP server using SSL. | N/A | 63 | 64 | ## Example 65 | 66 | ``` txt 67 | WinServ-Status.ps1 -List C:\foo\servers.txt -O C:\foo -DiskAlert 90 -CpuAlert 95 -MemAlert 85 -Refresh 300 -Light 68 | ``` 69 | 70 | Using the switches above the script will execute using the list of servers and output a HTML report to C:\foo. The disk usage alert will highlight at 90% usage for any one drive, the CPU usage alert will highlight at 95% usage, and the memory usage alert will highlight at 85% usage. The status of the servers will refresh every 5 minutes, and the HTML file will have a light theme instead of a dark theme. 71 | 72 | ## Change Log 73 | 74 | ### 2019-09-04 v1.7 75 | 76 | * Added custom subject line for e-mail. 77 | 78 | ### 2019-02-23 v1.6 79 | 80 | * Updated the style of the web page with a cleaner look. 81 | * Added 'online' CSS animation when the web page is in monitor mode - this is configured by using the refresh switch. It will not display when in report mode (no refresh switch). 82 | 83 | ### 2018-06-10 v1.5 84 | 85 | * Added light theme for the web page. 86 | * Added ability to export a CSV file instead of a web page. 87 | * Improved the Offline visual effect on the web page. 88 | 89 | ### 2018-05-24 v1.4 90 | 91 | * Servers are now sorted alphabetically, regardless of how they are entered in the text file. 92 | * Offline servers are automatically shuffled to the top of the report. 93 | * Added validation for the command line parameters. 94 | * Removed IP addresses, and table headers to make room for more information. 95 | * Due to removing table headers, added component name to CPU and RAM usage columns. 96 | * Added new effect using CSS animation for offline servers. 97 | * Added different shade of black for alternate table rows. 98 | 99 | ### 2017-10-16 v1.3 100 | 101 | * Changed SMTP authentication to require an encrypted password file. 102 | * Added instructions on how to generate an encrypted password file. 103 | 104 | ### 2017-10-09 v1.2 105 | 106 | * Added necessary information to add the script to the PowerShell Gallery. 107 | 108 | ### 2018-09-27 v1.1 109 | 110 | * Added capability for the script to run and monitor server status continuously. 111 | * Added icons to warning and error states to assist in at-a-glace reporting. 112 | * Added memory and CPU usage. 113 | * Added warning thresholds for memory and CPU usage. 114 | * Changed disk usage reporting from "percent free" to actual disk usage to match the added CPU and memory usage. 115 | * Changed the warning threshold to of disk usage to match the change. 116 | * Changed the visual style of the report. 117 | * Changed visual style of warnings and errors. 118 | * Changed code formatting for readability. 119 | 120 | ### 2017-07-28 v1.0 121 | 122 | * First public release. 123 | -------------------------------------------------------------------------------- /WinServ-Status.ps1: -------------------------------------------------------------------------------- 1 | <#PSScriptInfo 2 | 3 | .VERSION 1.7 4 | 5 | .GUID 2cb94e4f-1e85-4712-9441-91abcaea8572 6 | 7 | .AUTHOR Mike Galvin Contact: digressive@outlook.com & Dan Price twitter.com/therezin, based on code by Bhavik Solanki. 8 | 9 | .COMPANYNAME Mike Galvin 10 | 11 | .COPYRIGHT (C) Mike Galvin. All rights reserved. 12 | 13 | .TAGS Windows Server Status Report Monitor 14 | 15 | .LICENSEURI https://github.com/Digressive/Windows-Server-Status-Monitor?tab=MIT-1-ov-file 16 | 17 | .PROJECTURI https://gal.vin/posts/windows-server-status/ 18 | 19 | .ICONURI 20 | 21 | .EXTERNALMODULEDEPENDENCIES 22 | 23 | .REQUIREDSCRIPTS 24 | 25 | .EXTERNALSCRIPTDEPENDENCIES 26 | 27 | .RELEASENOTES 28 | 29 | #> 30 | 31 | <# 32 | .SYNOPSIS 33 | Creates a status report of Windows Servers. 34 | 35 | .DESCRIPTION 36 | Creates a status report of Windows Servers. 37 | 38 | This script will: 39 | 40 | Generate a status report from a list of Windows servers. 41 | The report will highlight information if the alert threshold is exceeded. 42 | 43 | Please note: to send a log file using ssl and an SMTP password you must generate an encrypted 44 | password file. The password file is unique to both the user and machine. 45 | 46 | The command is as follows: 47 | 48 | $creds = Get-Credential 49 | $creds.Password | ConvertFrom-SecureString | Set-Content C:\scripts\ps-script-pwd.txt 50 | 51 | .PARAMETER List 52 | The path to a TXT file containing the netbios names of the servers you wish to check. 53 | 54 | .PARAMETER O 55 | The path where the report file will be output to. 56 | 57 | .PARAMETER DiskAlert 58 | The percentage of disk usage that should cause the disk space alert to be raised. 59 | 60 | .PARAMETER CpuAlert 61 | The percentage of CPU usage that should cause the CPU alert to be raised. 62 | 63 | .PARAMETER MemAlert 64 | The percentage of memory usage that should cause the memory alert to be raised. 65 | 66 | .PARAMETER Refresh 67 | The number of seconds that she script should wait before running again. The minimum is 300 seconds (5 minutes) 68 | and the maximum is 28800 (8 hours). If not configured the script will run once and then end. 69 | 70 | .PARAMETER Light 71 | Configure the HTML results file to have a light theme. 72 | 73 | .PARAMETER csv 74 | Export a CSV file, instead of a HTML file. 75 | 76 | .PARAMETER Subject 77 | The email subject that the email should have. Encapulate with single or double quotes. 78 | 79 | .PARAMETER SendTo 80 | The e-mail address the status page should be sent to. 81 | 82 | .PARAMETER From 83 | The e-mail address the status page should be sent from. 84 | 85 | .PARAMETER Smtp 86 | The DNS name or IP address of the SMTP server. 87 | 88 | .PARAMETER User 89 | The user account to connect to the SMTP server. 90 | 91 | .PARAMETER Pwd 92 | The txt file containing the encrypted password for the user account. 93 | 94 | .PARAMETER UseSsl 95 | Configures the script to connect to the SMTP server using SSL. 96 | 97 | .EXAMPLE 98 | WinServ-Status.ps1 -List C:\foo\servers.txt -O C:\foo -DiskAlert 90 -CpuAlert 95 -MemAlert 85 -Refresh 300 -Light 99 | Using the switches above the script will execute using the list of servers and output a HTML report to C:\foo. 100 | The disk usage alert will highlight at 90% usage for any one drive, the CPU usage alert will highlight at 95% usage, 101 | and the memory usage alert will highlight at 85% usage. The status of the servers will refresh every 5 minutes, and 102 | the web page will have a light theme instead of a dark theme. 103 | #> 104 | 105 | ## Set up command line switches and what variables they map to. 106 | [CmdletBinding()] 107 | Param( 108 | [Parameter(Mandatory=$True)] 109 | [Alias("List")] 110 | [ValidateScript({Test-Path -Path $_ -PathType Leaf})] 111 | [string]$ServerFile, 112 | [Parameter(Mandatory=$True)] 113 | [Alias("O")] 114 | [ValidateScript({Test-Path $_ -PathType 'Container'})] 115 | [string]$OutputPath, 116 | [Alias("DiskAlert")] 117 | [ValidateRange(0,100)] 118 | [int]$DiskAlertThreshold, 119 | [Alias("CpuAlert")] 120 | [ValidateRange(0,100)] 121 | [int]$CpuAlertThreshold, 122 | [Alias("MemAlert")] 123 | [ValidateRange(0,100)] 124 | [int]$MemAlertThreshold, 125 | [Alias("Refresh")] 126 | [ValidateRange(300,28800)] 127 | [int]$RefreshTime, 128 | [switch]$Light, 129 | [switch]$csv, 130 | [alias("Subject")] 131 | [string]$MailSubject, 132 | [Alias("SendTo")] 133 | [string]$MailTo, 134 | [Alias("From")] 135 | [string]$MailFrom, 136 | [Alias("Smtp")] 137 | [string]$SmtpServer, 138 | [Alias("User")] 139 | [string]$SmtpUser, 140 | [Alias("Pwd")] 141 | [string]$SmtpPwd, 142 | [switch]$UseSsl) 143 | 144 | ## Function to get the up time from a server. 145 | Function Get-UpTime 146 | { 147 | param([string] $LastBootTime) 148 | $Uptime = (Get-Date) - [System.Management.ManagementDateTimeconverter]::ToDateTime($LastBootTime) 149 | "$($Uptime.Days) days $($Uptime.Hours)h $($Uptime.Minutes)m" 150 | } 151 | 152 | ## Begining of the loop. At the bottom of the script the loop is broken if the refresh option is not configured. 153 | Do 154 | { 155 | ## If CSV is configured, setting the location and name of the report output. If CSV is not configured output a HTML file. 156 | If ($csv) 157 | { 158 | $OutputFile = "$OutputPath\WinServ-Status-Report.csv" 159 | 160 | ## If the CSV file already exists, clear it 161 | $csvT = Test-Path -Path $OutputFile 162 | 163 | If ($csvT) 164 | { 165 | Clear-Content -Path $OutputFile 166 | } 167 | } 168 | 169 | Else 170 | { 171 | $OutputFile = "$OutputPath\WinServ-Status-Report.htm" 172 | } 173 | 174 | $ServerList = Get-Content $ServerFile 175 | $Result = @() 176 | 177 | ## Using variables for HTML and CSS so we don't need to use escape characters below. 178 | $Green = "00e600" 179 | $Grey = "e6e6e6" 180 | $Red = "ff4d4d" 181 | $Black = "1a1a1a" 182 | $Yellow = "ffff4d" 183 | $CssError = "error" 184 | $CssFormat = "format" 185 | $CssSpinner = "spinner" 186 | $CssRect1 = "rect1" 187 | $CssRect2 = "rect2" 188 | $CssRect3 = "rect3" 189 | $CssRect4 = "rect4" 190 | $CssRect5 = "rect5" 191 | 192 | ## Sort Servers based on whether they are online or offline 193 | $ServerList = $ServerList | Sort-Object 194 | 195 | ForEach ($ServerName in $ServerList) 196 | { 197 | $PingStatus = Test-Connection -ComputerName $ServerName -Count 1 -Quiet 198 | 199 | If ($PingStatus -eq $False) 200 | { 201 | $ServersOffline += @($ServerName) 202 | } 203 | 204 | Else 205 | { 206 | $ServersOnline += @($ServerName) 207 | } 208 | } 209 | 210 | $ServerListFinal = $ServersOffline + $ServersOnline 211 | 212 | ## Look through the final servers list. 213 | ForEach ($ServerName in $ServerListFinal) 214 | { 215 | $PingStatus = Test-Connection -ComputerName $ServerName -Count 1 -Quiet 216 | 217 | ## If server responds, get the stats for the server. 218 | If ($PingStatus) 219 | { 220 | $CpuAlert = $false 221 | $MemAlert = $false 222 | $DiskAlert = $false 223 | $OperatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName $ServerName 224 | $CpuUsage = Get-WmiObject Win32_Processor -Computername $ServerName | Measure-Object -Property LoadPercentage -Average | ForEach-Object {$_.Average; If($_.Average -ge $CpuAlertThreshold){$CpuAlert = $True};} 225 | $Uptime = Get-Uptime($OperatingSystem.LastBootUpTime) 226 | $MemUsage = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $ServerName | ForEach-Object {“{0:N0}” -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) * 100)/ $_.TotalVisibleMemorySize); If((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory) * 100)/ $_.TotalVisibleMemorySize -ge $MemAlertThreshold){$MemAlert = $True};} 227 | $DiskUsage = Get-WmiObject Win32_LogicalDisk -ComputerName $ServerName | Where-Object {$_.DriveType -eq 3} | Foreach-Object {$_.DeviceID, [Math]::Round((($_.Size - $_.FreeSpace) * 100)/ $_.Size); If([Math]::Round((($_.Size - $_.FreeSpace) * 100)/ $_.Size) -ge $DiskAlertThreshold){$DiskAlert = $True};} 228 | } 229 | 230 | ## Put the results together in an array. 231 | $Result += New-Object PSObject -Property @{ 232 | ServerName = $ServerName 233 | Status = $PingStatus 234 | CpuUsage = $CpuUsage 235 | CpuAlert = $CpuAlert 236 | Uptime = $Uptime 237 | MemUsage = $MemUsage 238 | MemAlert = $MemAlert 239 | DiskUsage = $DiskUsage 240 | DiskAlert = $DiskAlert 241 | } 242 | 243 | ## Clear the variables after obtaining and storing the results, otherwise data is duplicated. 244 | If ($ServerListFinal) 245 | { 246 | Clear-Variable ServerListFinal 247 | } 248 | 249 | If ($ServersOffline) 250 | { 251 | Clear-Variable ServersOffline 252 | } 253 | 254 | If ($ServersOnline) 255 | { 256 | Clear-Variable ServersOnline 257 | } 258 | 259 | If ($PingStatus) 260 | { 261 | Clear-Variable PingStatus 262 | } 263 | 264 | If ($CpuUsage) 265 | { 266 | Clear-Variable CpuUsage 267 | } 268 | 269 | If ($Uptime) 270 | { 271 | Clear-Variable Uptime 272 | } 273 | 274 | If ($MemUsage) 275 | { 276 | Clear-Variable MemUsage 277 | } 278 | 279 | If ($DiskUsage) 280 | { 281 | Clear-Variable DiskUsage 282 | } 283 | } 284 | 285 | ## If there is a result put the report together. 286 | If ($Null -ne $Result) 287 | { 288 | ## If CSV report is specified, output a CSV file. If CSV is not configured output a HTML file. 289 | If ($csv) 290 | { 291 | ForEach($Entry in $Result) 292 | { 293 | If ($Entry.Status -eq $True) 294 | { 295 | Add-Content -Path "$OutputFile" -Value "$($Entry.ServerName),Online,CPU: $($Entry.CpuUsage),Mem: $($Entry.MemUsage),$($Entry.DiskUsage),$($Entry.Uptime)" 296 | } 297 | 298 | Else 299 | { 300 | Add-Content -Path "$OutputFile" -Value "$($Entry.ServerName),Offline" 301 | } 302 | } 303 | } 304 | 305 | Else 306 | { 307 | ## If the light theme is specified, use a lighter css theme. If not, use the dark css theme. 308 | If ($Light) 309 | { 310 | $HTML = ' 330 |
' 331 | 332 | $HTML += " 333 |Last update: $(Get-Date -Format G)
334 |OFFL | "
381 | }
382 | }
383 |
384 | If ($Entry.Status -eq $True)
385 | {
386 | $HTML += "$($Entry.ServerName) | "
387 | }
388 |
389 | Else
390 | {
391 | $HTML += "$($Entry.ServerName) | "
392 | }
393 |
394 | If ($Null -ne $Entry.CpuUsage)
395 | {
396 | If ($Entry.CpuAlert -eq $True)
397 | {
398 | $HTML += "CPU: $($Entry.CpuUsage)% | "
399 | }
400 |
401 | Else
402 | {
403 | $HTML += "CPU: $($Entry.CpuUsage)% | "
404 | }
405 | }
406 |
407 | Else
408 | {
409 | $HTML += "OFFL | "
410 | }
411 |
412 | If ($Null -ne $Entry.MemUsage)
413 | {
414 | If ($Entry.MemAlert -eq $True)
415 | {
416 | $HTML += "Mem: $($Entry.MemUsage)% | "
417 | }
418 |
419 | Else
420 | {
421 | $HTML += "Mem: $($Entry.MemUsage)% | "
422 | }
423 | }
424 |
425 | Else
426 | {
427 | $HTML += "OFFL | "
428 | }
429 |
430 | If ($Null -ne $Entry.DiskUsage)
431 | {
432 | If ($Entry.DiskAlert -eq $True)
433 | {
434 | $HTML += "$($Entry.DiskUsage)% | "
435 | }
436 |
437 | Else
438 | {
439 | $HTML += "$($Entry.DiskUsage)% | "
440 | }
441 | }
442 |
443 | Else
444 | {
445 | $HTML += "OFFL | "
446 | }
447 |
448 | If ($Entry.Status -eq $True)
449 | {
450 | $HTML += "$($Entry.Uptime) |
451 | "
452 | }
453 |
454 | Else
455 | {
456 | $HTML += "OFFL |
457 | "
458 | }
459 | }
460 |
461 | ## Finish the HTML file.
462 | $HTML += "