PowerShell: Windows Server Status Monitor (Update 1.3)

I wanted to create a script to generate a status report from a list of servers. It needed to highlight any metrics that were outside of a customization threshold visually and be able to e-mail the report or run continuously and be a rudimentary system monitor. Based on a script from Bhavik Solanki (on TechNet) and with some help from my good friend, and .Net developer Dan Price, we created WinServ-Status.

This script is available to download from the Microsoft TechNet Gallery and the PowerShell Gallery.

Features and Requirements

The script will do the following:

  • Display the server name and IP address.
  • Display Online/Offline status.
  • Display CPU usage, customisable alert.
  • Display memory usage, with a customisable alert.
  • Display the disk space usage for each volume, with a customisable alert.
  • Display server uptime.
  • Can be configured to run and monitor continuously.
  • Can be configured as a “one shot” status report.
  • Can be configured to e-mail the report.

The script 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.

Generating an encrypted password file

If you’ve used a previous version I’ve changed how the script handles configuring a password for the log notification e-mail. Specifically the password must now be in an encrypted text file. The advantage of this is that the password will no longer be in plain text, which is a security risk. The downside is that you will now need to generate a password file. The command to do this is pretty simple, but it must be generated on the computer the script will be running on, and as the user used to run the script.

To generate the password file, run the following command in PowerShell. When running the command you will be prompted for a username and password. The username doesn’t matter and can be anything, but the password must be the password you want to use to authenticate to your SMTP server.

$creds = Get-Credential
$creds.Password | ConvertFrom-SecureString | Set-Content c:\scripts\ps-script-pwd.txt

After running the commands, you should have a text file contained the encrypted password. Enter the path and filename for the -pwd switch to configure authenticated e-mail notification.


The configuration of the script can be done via command line switches. Here’s a list of all the switches and examples.

Command Line Switch Mandatory Description Example
-list Yes The text file with the servers you wish to check. C:\scripts\Servers.txt
-o Yes The location to store the HTML file. C:\scripts
-cpualert No The minimum percentage of usage that alert status should be raised. 95
-diskalert No The minimum percentage of usage that alert status should be raised. 85
-memalert No The minimum percentage of usage that alert status should be raised. 90
-refresh No The number of seconds the script should wait before refreshing the status.

The webpage auto refreshes every 30 seconds, so the lowest this value  should be set is 30.

I recommend for 20+ servers that this number shouldn’t be lower than 60 seconds.

-sendto No The email address to send the report to. me@contoso.com
-from No* The email address that the report should be sent from.

*This switch isn’t mandatory but is required if you wish to email the report.

-smtp No* SMTP server address to use for the email functionality.

*This switch isn’t mandatory but is required if you wish to email the report.






-user No* The username of the account to use for SMTP authentication.

*This switch isn’t mandatory but may be required depending on the configuration of the SMTP server.

-pwd No* The location of the file containing the encrypted password of the account to use for SMTP authentication.

*This switch isn’t mandatory but may be required depending on your SMTP server.


-usessl No* Add this option if you wish to use SSL with the configured SMTP server.

Tip: If you wish to send email to outlook.com or office365.com you will need this.

*This switch isn’t mandatory but may be required depending on the configuration of the SMTP server.


Change Log

16/10/2017 1.3

  • Changed SMTP authentication to require an encrypted password file.
  • Added instructions on how to generate an encrypted password file.

09/10/2017 1.2

  • Added necessary information to add the script to the PowerShell Gallery.

27/09/2017 1.1

  • Added capability for the script to run and monitor server status continuously.
  • Added icons to warning and error states to assist in at-a-glace reporting.
  • Added memory and CPU usage.
  • Added warning thresholds for memory and CPU usage.
  • Changed disk usage reporting from “percent free” to actual disk usage to match the added CPU and memory usage.
  • Changed the warning threshold to of disk usage to match the change.
  • Changed the visual style of the report.
  • Changed visual style of warnings and errors.
  • Changed code formatting for readability.

28/07/2017 1.0

  • First public release.

PowerShell Code

<#PSScriptInfo .VERSION 1.3 .GUID 2cb94e4f-1e85-4712-9441-91abcaea8572 .AUTHOR Mike Galvin twitter.com/digressive & Dan Price twitter.com/therezin, based on code by Bhavik Solanki. .COMPANYNAME .COPYRIGHT (C) Mike Galvin. All rights reserved. .TAGS Windows Server Status Report Monitor .LICENSEURI .PROJECTURI https://gal.vin/2017/07/28/windows-server-status/ .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #>

<# .SYNOPSIS Creates a status report of Windows Servers. .DESCRIPTION Creates a status report of Windows Servers. This script will: Generate a HTML status report from a configurable list of Windows servers. The report will highlight information is the alert threashold is exceeded. Please note: to send a log file using ssl and an SMTP password you must generate an encrypted password file. The password file is unique to both the user and machine. The command is as follows: $creds = Get-Credential $creds.Password | ConvertFrom-SecureString | Set-Content c:\foo\ps-script-pwd.txt .PARAMETER List The path to a text file with a list of server names to monitor. .PARAMETER O The path where the HTML report should be output to. The filename will be WinServ-Status-Report.htm. .PARAMETER DiskAlert The percentage of disk usage that should cause the disk space alert to be raised. .PARAMETER CpuAlert The percentage of CPU usage that should cause the CPU alert to be raised. .PARAMETER MemAlert The percentage of memory usage that should cause the memory alert to be raised. .PARAMETER Refresh The number of seconds that she script should wait before running again. If not configured the script will run once and then exit. .PARAMETER SendTo The e-mail address the log should be sent to. .PARAMETER From The from address the log should be sent from. .PARAMETER Smtp The DNS or IP address of the SMTP server. .PARAMETER User The user account to connect to the SMTP server. .PARAMETER Pwd The password for the user account. .PARAMETER UseSsl Connect to the SMTP server using SSL. .EXAMPLE WinServ-Status.ps1 -List C:\foo\servers.txt -O C:\foo -DiskAlert 90 -CpuAlert 95 -MemAlert 85 -Refresh 120 The script will execute using the list of servers and output a html report called WinServ-Status-Report.htm 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 script will re-run every 2 minutes. #>

## Set up command line switches and what variables they map to

## Function to get the up time from the server
Function Get-UpTime
    param([string] $LastBootTime)
    $Uptime = (Get-Date) - [System.Management.ManagementDateTimeconverter]::ToDateTime($LastBootTime)
    "$($Uptime.Days) days $($Uptime.Hours)h $($Uptime.Minutes)m"

## Begining of the loop. Lower down the loop is broken if the refresh option is not configured.
    ## Change value of the following parameter as needed
    $OutputFile = "$OutputPath\WinServ-Status-Report.htm"
    $ServerList = Get-Content $ServerFile
    $Result = @()

    ## Look through the servers in the file provided
    ForEach ($ServerName in $ServerList)
        $PingStatus = Test-Connection -ComputerName $ServerName -Count 1 -Quiet

        ## If server responds, get uptime and disk info
        If ($PingStatus)
            $OperatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName $ServerName
            $CpuAlert = $false
            $CpuUsage = Get-WmiObject Win32_Processor -Computername $ServerName | Measure-Object -Property LoadPercentage -Average | ForEach-Object {$_.Average; If($_.Average -ge $CpuAlertThreshold){$CpuAlert = $True}; "%"}
            $Uptime = Get-Uptime($OperatingSystem.LastBootUpTime)
            $MemAlert = $false
            $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}; "%"}
            $DiskAlert = $false
            $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}; "%"}
            $IPv4Address = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ServerName | Select-Object -Expand IPAddress | Where-Object { ([Net.IPAddress]$_).AddressFamily -eq "InterNetwork" }
        ## Put the results together
        $Result += New-Object PSObject -Property @{
	        ServerName = $ServerName
		    IPV4Address = $IPv4Address
		    Status = $PingStatus
            CpuUsage = $CpuUsage
            CpuAlert = $CpuAlert
		    Uptime = $Uptime
            MemUsage = $MemUsage
            MemAlert = $MemAlert
            DiskUsage = $DiskUsage
            DiskAlert = $DiskAlert

        ## Clear the variables after obtaining and storing the results so offline servers don't have duplicate info.
        Clear-Variable IPv4Address
        Clear-Variable Uptime
        Clear-Variable MemUsage
        Clear-Variable CpuUsage
        Clear-Variable DiskUsage

    ## If there is a result put the HTML file together.
    If ($Result -ne $null)
     ## HTML Code goes here! HTML doesn't format properly with PowerShell on WordPress. Download the script from TechNet or the PowerShell Gallery to see the complete code!
        ## Output the HTML file
	    $HTML | Out-File $OutputFile

        ## If email was configured, set the variables for the email subject and body
        If ($SmtpServer)
            $MailSubject = "Server Status Report"
            $MailBody = Get-Content -Path $OutputFile | Out-String

            ## If an email password was configured, create a variable with the username and password
            If ($SmtpPwd)
                $SmtpPwdEncrypt = Get-Content $SmtpPwd | ConvertTo-SecureString
                $SmtpCreds = New-Object System.Management.Automation.PSCredential -ArgumentList ($SmtpUser, $SmtpPwdEncrypt)

                ## If ssl was configured, send the email with ssl
                If ($UseSsl)
                    Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -BodyAsHtml -SmtpServer $SmtpServer -UseSsl -Credential $SmtpCreds

                ## If ssl wasn't configured, send the email without ssl
                    Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -BodyAsHtml -SmtpServer $SmtpServer -Credential $SmtpCreds

            ## If an email username and password were not configured, send the email without authentication
                Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $MailBody -BodyAsHtml -SmtpServer $SmtpServer

        ## If the refresh time option is configured, wait the specifed number of seconds then loop.
        If ($RefreshTime -ne $null)
            Start-Sleep -Seconds $RefreshTime

## If the refresh time option is not configured, stop the loop.
Until ($RefreshTime -eq $null)

## End

If you’d like to get in touch with me, please leave a comment or tweet me.


Follow Mike on Twitter: @Digressive

4 Comments Add yours

  1. Meer says:

    Hi Mike .. really nice script …just have one question here ..how can i schedule this script to run every 8 hour


    1. Mike Galvin says:

      Hi Meer,

      Please disregard my previous reply, I was under the impression you were asking about the Hyper-V-Backup script.

      For the WinServStatus script to refresh every 8 hours, you should be able to set the refresh option to -Refresh 28800



  2. Senthil Rajna says:

    Hi Mike, while I run the script I can see the output has Offline, do I missing anything?


    1. Mike Galvin says:

      Hi Senthil,

      You might need to check your account privileges, or it could be the network access on the computer running the script, and if it has access to the servers in the list to check. Without more info, it can be difficult to be sure



Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s