Abstract

Monitoring disk space utilization of server(s) is a critical and important job for any administrator. Keeping things organized might improve application availability and server availability.This article takes us through the in-detail steps to read servers from a text file and validate the disk based on default/custom threshold values. The output is integrated with HTML tags. You'll basically feed a list of servers to watch over, and it will report back on these for you, meaning you could also use it as a more general "daily server disk space report"

Introduction


This post explains how to monitor DiskSpace of a group of listed servers. The threshold values are set the globally. The values can also be customized as per your requirement. The function Get-DiskSpaceReport comprises of various cmdLets and function to monitor disk drives. 
  • Querying Get-Win32LogicalDisks
  • Use default or custom threshold values for all the listed servers
  • Prepare CSS HTML document
  • Validate the Freespace with reference to the disk threshold value and set the background color 
  • Email Address validation
  • HTML Output
You can customize it as per your requirement.

The Function Get-DiskSpaceReport has six input parameters:-
  1. ComputerList – List of Servers – Path of an input file where servers are listed
  2. Warning – Warning Threshold – Default = 25%
  3. Critical – Critical Threshold – Default =15%
  4. SMTPMail – SMTP mail address
  5. FromID – Valid Email ID
  6. ToID – Valid Email ID

Examples

Example 1:- Execute with default threshold values. By default, the threshold is set to 25(Warning) and 15(Critical)

PS:\>Get-DiskSpaceReport -ComputerList c:\computer.txt  -To pjayaram@Appvion.com -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com

Example 2:- Customize the default threshold values

PS:\>Get-DiskSpaceReport -ComputerList c:\computer.txt -warning 15 -critical 10 -To pjayaram@Appvion.com -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com

Example 3: Multiple recipients 

Get-DiskSpaceReport -ComputerList c:\computer.txt -warning 25 -critical 15 -To "pjayaram@Appvion.com,prashanth.jayaram@cognizant.com" -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com

Code In Detail


Output filename 

The below code defines the output file location and filename. Change the location or filename as per your requirement. 

$filename= "c:\freespace.htm"
New-Item -ItemType file $freeSpaceFileName -Force

The New-item   cmdlet creates an item.

-Force

Forces this cmdlet to create an item that writes over an existing read-only item. Implementation varies from provider to provider. For more information, see about_Providers   . Even using the Force parameter, the cmdlet cannot override security restrictions.


Prepare HTML file using CSS

The Add-Content   cmdlet is used to prepare CSS HTML file. The cmdlet is to append the data to a text file. In this case its going to be a html file.

There are two ways of preparing HTML output. One is through ConvertTo-HTML and using cssri parameter which accepts style sheet path as its input and other one is through manually defining the CSS tags and building a HTML file. Its like building a HTML file with values and tags to be displayed in a file. If one has little bit of knowledge over CSS will help alot in this case.

The below code has modularized for simple understanding and easy to enhance the code if one has to make any changes to a template.



Code



Code with Email Validation and single recipient



<#
 
.SYNOPSIS       
    Name :  Disk Space Utilizaiton Report
    Description : Get disk space usage informations from remote server(s) with WMI and output HTML file
   
    Author : Prashanth Jayaram
      
    * Select list of servers from a text file
    * Use default or custom threshold values - common attribute set for all the servers
    * Get remote Servers informations with WMI and Powershell :
    * Disk (Disk type, letter, capacity in GB, free space in GB, % free , Status)
    * Email validation
    * HTML Output
      
.INPUT
    .csv file with servers to activate
  
.OUTPUTS
    Console outputs : You can alter the code to write the data to file or console   
  
.NOTES
    Version:        1.0
    Author:         Prashanth Jayaram
    Creation Date:  2016-26-09
    Purpose/Change: Initial script development
    
.EXAMPLE 1 - Using Default threshold values
 
Get-DiskSpaceReport -ComputerList c:\computer.txt  -To pjayaram@Appvion.com -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com
 
.EXAMPLE 2 - Setting threshold values
 
PS:\>Get-DiskSpaceReport -ComputerList c:\computer.txt -warning 15 -critical 10 -To pjayaram@Appvion.com -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com
     
#>
Function Get-DiskSpaceReport
{
param(
  [parameter(Mandatory=$True,position=0,HelpMessage="Please specify valid text file path consists of list of server")]
     [Alias("MachineName")]
     [string[]]$ComputerList,
[int]$warning,
[int]$critical,
[parameter(Mandatory=$true][string]$EmailTo,
[parameter(Mandatory=$true][string]$EmailFrom,
[parameter(Mandatory=$true][string]$SMTPMail
)
 
 
$script:list = $ComputerList
 
$freeSpaceFileName = "C:\FreeSpace.htm"
 
if ($Warning -eq "$NULL")
{
$Warning=25
}
if ($critical -eq "$NULL")
{
$critical=15
}
$critical = $critical
$warning = $warning
 
 
New-Item -ItemType file $freeSpaceFileName -Force
 
 
# Getting the freespace info using WMI
#Get-WmiObject win32_logicaldisk  | Where-Object {$_.drivetype -eq 3 -OR $_.drivetype -eq 2 } | format-table DeviceID, VolumeName,status,Size,FreeSpace | Out-File FreeSpace.txt
# Function to write the HTML Header to the file
Function writeHtmlHeader
{
param($fileName)
$date = ( get-date ).ToString('yyyy/MM/dd')
Add-Content $fileName "<html>"
Add-Content $fileName "<head>"
Add-Content $fileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>"
Add-Content $fileName '<title>DiskSpace Report</title>'
add-content $fileName '<STYLE TYPE="text/css">'
add-content $fileName  "<!--"
add-content $fileName  "td {"
add-content $fileName  "font-family: Tahoma;"
add-content $fileName  "font-size: 11px;"
add-content $fileName  "border-top: 1px solid #999999;"
add-content $fileName  "border-right: 1px solid #999999;"
add-content $fileName  "border-bottom: 1px solid #999999;"
add-content $fileName  "border-left: 1px solid #999999;"
add-content $fileName  "padding-top: 0px;"
add-content $fileName  "padding-right: 0px;"
add-content $fileName  "padding-bottom: 0px;"
add-content $fileName  "padding-left: 0px;"
add-content $fileName  "}"
add-content $fileName  "body {"
add-content $fileName  "margin-left: 5px;"
add-content $fileName  "margin-top: 5px;"
add-content $fileName  "margin-right: 0px;"
add-content $fileName  "margin-bottom: 10px;"
add-content $fileName  ""
add-content $fileName  "table {"
add-content $fileName  "border: thin solid #000000;"
add-content $fileName  "}"
add-content $fileName  "-->"
add-content $fileName  "</style>"
Add-Content $fileName "</head>"
Add-Content $fileName "<body>"
add-content $fileName  "<table width='100%'>"
add-content $fileName  "<tr bgcolor='#CCCCCC'>"
add-content $fileName  "<td colspan='7' height='25' align='center'>"
add-content $fileName  "<font face='tahoma' color='#003399' size='4'><strong>DiskSpace Report - $date</strong></font>"
add-content $fileName  "</td>"
add-content $fileName  "</tr>"
add-content $fileName  "</table>"
}
 
# Function to write the HTML Header to the file
Function writeTableHeader
{
param($fileName)
Add-Content $fileName "<tr bgcolor=#CCCCCC>"
Add-Content $fileName "<td width='10%' align='center'>Drive</td>"
Add-Content $fileName "<td width='50%' align='center'>Drive Label</td>"
Add-Content $fileName "<td width='10%' align='center'>Total Capacity(GB)</td>"
Add-Content $fileName "<td width='10%' align='center'>Used Capacity(GB)</td>"
Add-Content $fileName "<td width='10%' align='center'>Free Space(GB)</td>"
Add-Content $fileName "<td width='10%' align='center'>Freespace %</td>"
Add-Content $fileName "</tr>"
}
 
Function writeHtmlFooter
{
param($fileName)
 
Add-Content $fileName "</body>"
Add-Content $fileName "</html>"
}
 
Function writeDiskInfo
{
param($fileName,$devId,$volName,$frSpace,$totSpace)
$totSpace=[math]::Round(($totSpace/1073741824),2)
$frSpace=[Math]::Round(($frSpace/1073741824),2)
$usedSpace = $totSpace - $frspace
$usedSpace=[Math]::Round($usedSpace,2)
$freePercent = ($frspace/$totSpace)*100
$freePercent = [Math]::Round($freePercent,0)
if ($freePercent -gt $warning)
{
Add-Content $fileName "<tr>"
Add-Content $fileName "<td>$devid</td>"
Add-Content $fileName "<td>$volName</td>"
 
Add-Content $fileName "<td>$totSpace</td>"
Add-Content $fileName "<td>$usedSpace</td>"
Add-Content $fileName "<td>$frSpace</td>"
Add-Content $fileName "<td>$freePercent</td>"
Add-Content $fileName "</tr>"
}
elseif ($freePercent -le $critical)
{
Add-Content $fileName "<tr>"
Add-Content $fileName "<td>$devid</td>"
Add-Content $fileName "<td>$volName</td>"
Add-Content $fileName "<td>$totSpace</td>"
Add-Content $fileName "<td>$usedSpace</td>"
Add-Content $fileName "<td>$frSpace</td>"
Add-Content $fileName "<td bgcolor='#FF0000' align=center>$freePercent</td>"
#<td bgcolor='#FF0000' align=center>
Add-Content $fileName "</tr>"
}
else
{
Add-Content $fileName "<tr>"
Add-Content $fileName "<td>$devid</td>"
Add-Content $fileName "<td>$volName</td>"
Add-Content $fileName "<td>$totSpace</td>"
Add-Content $fileName "<td>$usedSpace</td>"
Add-Content $fileName "<td>$frSpace</td>"
Add-Content $fileName "<td bgcolor='#FBB917' align=center>$freePercent</td>"
# #FBB917
Add-Content $fileName "</tr>"
}
}
 
writeHtmlHeader $freeSpaceFileName
foreach ($server in Get-Content $script:list)
{
if(Test-Connection -ComputerName $server -Count 1 -ea 0) {
Add-Content $freeSpaceFileName "<table width='100%'><tbody>"
Add-Content $freeSpaceFileName "<tr bgcolor='#CCCCCC'>"
Add-Content $freeSpaceFileName "<td width='100%' align='center' colSpan=6><font face='tahoma' color='#003399' size='2'><strong> $server </strong></font></td>"
Add-Content $freeSpaceFileName "</tr>"
 
writeTableHeader $freeSpaceFileName
 
$dp = Get-WmiObject win32_logicaldisk -ComputerName $server |  Where-Object {$_.drivetype -eq 3 }
foreach ($item in $dp)
{
Write-Host  $item.DeviceID  $item.VolumeName $item.FreeSpace $item.Size
writeDiskInfo $freeSpaceFileName $item.DeviceID $item.VolumeName $item.FreeSpace $item.Size
 
}
}
  Add-Content $freeSpaceFileName "</table>"
}
writeHtmlFooter $freeSpaceFileName
Function sendEmail 
{
param($from,$to,$subject,$smtphost,$htmlFileName) 
[string]$receipients="$to"
$body = Get-Content $htmlFileName
$body = New-Object System.Net.Mail.MailMessage $from, $receipients, $subject, $body
$body.isBodyhtml = $true
$smtpServer = $MailServer
$smtp = new-object Net.Mail.SmtpClient($smtphost)
$validfrom= Validate-IsEmail $from
if($validfrom -eq $TRUE)
{
$validTo= Validate-IsEmail $to
if($validTo -eq $TRUE)
{
$smtp.Send($body)
write-output "Email Sent!!"
 
}
}
else
{
write-output "Invalid entries, Try again!!"
}
}
 
# Email our report out
function Validate-IsEmail ([string]$Email)
{
           return $Email -match "^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$"
}
$date = ( get-date ).ToString('yyyy/MM/dd')
sendEmail -from $From -to $to -subject "Disk Space Report - $Date" -smtphost $SMTPMail -htmlfilename $freeSpaceFileName
}


Code for Multiple recipients with no email validation


<#
 
.SYNOPSIS       
    Name :  Disk Space Utilizaton Report
    Description : Get disk space usage information from remote server(s) with WMI and output HTML file
   
    Author : Prashanth Jayaram
      
    * Select list of servers from a text file
    * Use default or custom threshold values - common attribute set for all the servers
    * Get remote Servers information with WMI and PowerShell :
    * Disk (Disk type, letter, capacity in GB, free space in GB, % free , Status)
    * Email validation
    * HTML Output
      
.INPUT
    .csv file with servers to activate
  
.OUTPUTS
    Console outputs : You can alter the code to write the data to file or console   
  
.NOTES
    Version:        1.0
    Author:         Prashanth Jayaram
    Creation Date:  2016-26-09
    Purpose/Change: Initial script development
    
.EXAMPLE 1 - Using Default threshold values
 
Get-DiskSpaceReport -ComputerList c:\computer.txt  -To pjayaram@Appvion.com -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com
 
.EXAMPLE 2 - Setting threshold values
 
PS:\>Get-DiskSpaceReport -ComputerList c:\computer.txt -warning 15 -critical 10 -To pjayaram@Appvion.com -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com
  
 .EXAMPLE 3 - multiple receipients
 
PS:\>Get-DiskSpaceReport -ComputerList c:\computer.txt -warning 15 -critical 10 -To "pjayaram@Appvion.com,abc@appvion.com" -From pjayaram@appvion.com -SMTPMail qqma01.ppp.com  
 
#>
Function Get-DiskSpaceReport
{
param(
  [parameter(Mandatory=$True,position=0,HelpMessage="Please specify valid text file path consists of list of server")]
     [Alias("MachineName")]
     [string[]]$ComputerList,
[int]$warning,
[int]$critical,
[parameter(Mandatory=$true)][string]$EmailTo,
[parameter(Mandatory=$true)][string]$EmailFrom,
[parameter(Mandatory=$true)][string]$SMTPMail
)
 
 
$script:list = $ComputerList
 
$freeSpaceFileName = "C:\FreeSpace.htm"
 
if ($Warning -eq "$NULL")
{
$Warning=25
}
if ($critical -eq "$NULL")
{
$critical=15
}
$critical = $critical
$warning = $warning
 
 
New-Item -ItemType file $freeSpaceFileName -Force
 
 
# Getting the freespace info using WMI
#Get-WmiObject win32_logicaldisk  | Where-Object {$_.drivetype -eq 3 -OR $_.drivetype -eq 2 } | format-table DeviceID, VolumeName,status,Size,FreeSpace | Out-File FreeSpace.txt
# Function to write the HTML Header to the file
Function writeHtmlHeader
{
param($fileName)
$date = ( get-date ).ToString('yyyy/MM/dd')
Add-Content $fileName "<html>"
Add-Content $fileName "<head>"
Add-Content $fileName "<meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'>"
Add-Content $fileName '<title>DiskSpace Report</title>'
add-content $fileName '<STYLE TYPE="text/css">'
add-content $fileName  "<!--"
add-content $fileName  "td {"
add-content $fileName  "font-family: Tahoma;"
add-content $fileName  "font-size: 11px;"
add-content $fileName  "border-top: 1px solid #999999;"
add-content $fileName  "border-right: 1px solid #999999;"
add-content $fileName  "border-bottom: 1px solid #999999;"
add-content $fileName  "border-left: 1px solid #999999;"
add-content $fileName  "padding-top: 0px;"
add-content $fileName  "padding-right: 0px;"
add-content $fileName  "padding-bottom: 0px;"
add-content $fileName  "padding-left: 0px;"
add-content $fileName  "}"
add-content $fileName  "body {"
add-content $fileName  "margin-left: 5px;"
add-content $fileName  "margin-top: 5px;"
add-content $fileName  "margin-right: 0px;"
add-content $fileName  "margin-bottom: 10px;"
add-content $fileName  ""
add-content $fileName  "table {"
add-content $fileName  "border: thin solid #000000;"
add-content $fileName  "}"
add-content $fileName  "-->"
add-content $fileName  "</style>"
Add-Content $fileName "</head>"
Add-Content $fileName "<body>"
add-content $fileName  "<table width='100%'>"
add-content $fileName  "<tr bgcolor='#CCCCCC'>"
add-content $fileName  "<td colspan='7' height='25' align='center'>"
add-content $fileName  "<font face='tahoma' color='#003399' size='4'><strong>DiskSpace Report - $date</strong></font>"
add-content $fileName  "</td>"
add-content $fileName  "</tr>"
add-content $fileName  "</table>"
}
 
# Function to write the HTML Header to the file
Function writeTableHeader
{
param($fileName)
Add-Content $fileName "<tr bgcolor=#CCCCCC>"
Add-Content $fileName "<td width='10%' align='center'>Drive</td>"
Add-Content $fileName "<td width='50%' align='center'>Drive Label</td>"
Add-Content $fileName "<td width='10%' align='center'>Total Capacity(GB)</td>"
Add-Content $fileName "<td width='10%' align='center'>Used Capacity(GB)</td>"
Add-Content $fileName "<td width='10%' align='center'>Free Space(GB)</td>"
Add-Content $fileName "<td width='10%' align='center'>Freespace %</td>"
Add-Content $fileName "</tr>"
}
 
Function writeHtmlFooter
{
param($fileName)
 
Add-Content $fileName "</body>"
Add-Content $fileName "</html>"
}
 
Function writeDiskInfo
{
param($fileName,$devId,$volName,$frSpace,$totSpace)
$totSpace=[math]::Round(($totSpace/1073741824),2)
$frSpace=[Math]::Round(($frSpace/1073741824),2)
$usedSpace = $totSpace - $frspace
$usedSpace=[Math]::Round($usedSpace,2)
$freePercent = ($frspace/$totSpace)*100
$freePercent = [Math]::Round($freePercent,0)
if ($freePercent -gt $warning)
{
Add-Content $fileName "<tr>"
Add-Content $fileName "<td>$devid</td>"
Add-Content $fileName "<td>$volName</td>"
 
Add-Content $fileName "<td>$totSpace</td>"
Add-Content $fileName "<td>$usedSpace</td>"
Add-Content $fileName "<td>$frSpace</td>"
Add-Content $fileName "<td>$freePercent</td>"
Add-Content $fileName "</tr>"
}
elseif ($freePercent -le $critical)
{
Add-Content $fileName "<tr>"
Add-Content $fileName "<td>$devid</td>"
Add-Content $fileName "<td>$volName</td>"
Add-Content $fileName "<td>$totSpace</td>"
Add-Content $fileName "<td>$usedSpace</td>"
Add-Content $fileName "<td>$frSpace</td>"
Add-Content $fileName "<td bgcolor='#FF0000'>$freePercent</td>"
#<td bgcolor='#FF0000' align=center>
Add-Content $fileName "</tr>"
}
else
{
Add-Content $fileName "<tr>"
Add-Content $fileName "<td>$devid</td>"
Add-Content $fileName "<td>$volName</td>"
Add-Content $fileName "<td>$totSpace</td>"
Add-Content $fileName "<td>$usedSpace</td>"
Add-Content $fileName "<td>$frSpace</td>"
Add-Content $fileName "<td bgcolor='#FBB917'>$freePercent</td>"
# #FBB917
Add-Content $fileName "</tr>"
}
}
 
writeHtmlHeader $freeSpaceFileName
foreach ($server in Get-Content $script:list)
{
if(Test-Connection -ComputerName $server -Count 1 -ea 0) {
Add-Content $freeSpaceFileName "<table width='100%'><tbody>"
Add-Content $freeSpaceFileName "<tr bgcolor='#CCCCCC'>"
Add-Content $freeSpaceFileName "<td width='100%' align='center' colSpan=6><font face='tahoma' color='#003399' size='2'><strong> $server </strong></font></td>"
Add-Content $freeSpaceFileName "</tr>"
 
writeTableHeader $freeSpaceFileName
 
$dp = Get-WmiObject win32_logicaldisk -ComputerName $server |  Where-Object {$_.drivetype -eq 3 }
foreach ($item in $dp)
{
Write-Host  $item.DeviceID  $item.VolumeName $item.FreeSpace $item.Size
writeDiskInfo $freeSpaceFileName $item.DeviceID $item.VolumeName $item.FreeSpace $item.Size
 
}
}
  Add-Content $freeSpaceFileName "</table>"
}
writeHtmlFooter $freeSpaceFileName
 
Function sendEmail 
{
param($from,$to,$subject,$smtphost,$htmlFileName) 
[string]$receipients="$to"
$body = Get-Content $htmlFileName
$body = New-Object System.Net.Mail.MailMessage $from, $receipients, $subject, $body
$body.isBodyhtml = $true
$smtpServer = $MailServer
$smtp = new-object Net.Mail.SmtpClient($smtphost)
$smtp.Send($body)
}
 
# Email our report out
function Validate-IsEmail ([string]$Email)
{
           return $Email -match "^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$"
}
$date = ( get-date ).ToString('yyyy/MM/dd')
sendEmail -from $EmailFrom -to $Emailto -subject "Disk Space Report - $Date" -smtphost $SMTPMail -htmlfilename $freeSpaceFileName
}


Output
  


References



Blog

https://sqlpowershell.wordpress.com/2013/10/01/powershell-script-to-monitor-disk-space-of-a-group-of-servers-html-formatted-email-output/

github

https://github.com/mubix/PowerShell-1/blob/master/Report-DiskSpaceUsage.ps1