Introduction
In the previous three blog posts (one, two and three) we have scripts that are monitoring for IIS Logs as well as IMAP/POP logs that may be taking up space. We also reviewed how to monitor our Exchange Databases for proper backups which will ensure the logs get properly truncated and keep disk space lower for this part of Exchange. However, for monitoring servers we may need a broader picture of the space available on all drives, System, Pagefile, Application, Temp and so on. With a PowerShell script we can analyze each volume of a server for the amount of free space and report on those volumes which appear to be at risk of running out of space.
Building the Script
With reporting or other data manipulations, simply retrieving disk space for each volume on a given server is rather short script with just a few steps to normalize the date. A sample script can be found here:
List of Exchange Databases
As this script will need to analyze each Exchange Server, we’ll need to pull that list. To make the list cleaner we will select just the name and then sort that list. All of this can be done with one line:
$Databases = Get-MailboxDatabase -Status
Export file for Reporting
# File definitions $FreeSpaceResults = 'C:\DiskSpace\FreeSpace.csv' $Export = 'Server,Name,FreeSpace,DriveSize,PercentFree' | Out-file $FreeSpaceresults
Start Loop for Each Exchange Server
Foreach ($ExchangeServer in $Exchangeservers) {
Start Loop for Each Exchange Server
$Volumes = Get-Volume -CimSession $ExchangeServer | Sort FileSystemLabel
Calculate some Volume Size Stats
$Size = ($Volume.Size)/1GB $SizeRemaining = ($Volume.SizeRemaining)/1GB $PercentFree = [Math]::Round($($SizeRemaining/$Size),4) $SizeR = [Math]::Round(($Volume.Size)/1GB,2) $SizeRemainingR = [Math]::Round(($Volume.SizeRemaining)/1GB,2) $P = $PercentFree.toString('p')
Export the Size Stat Results to a file
$Name=$Volume.FileSystemLabel $Server=$ExchangeServer.Name $Export += "$Server,$Name,$SizeRemainingR,$SizeR,$P" | Out-File $FreeSpaceResults -Append
Sample Report File
Larger Script with Email Reporting
Taking what we have from the above code and using PS Objects, sorting, etc, we can create a scrip that will provide a detailed report of space on each Exchange Server. Note that the script could be tailored to Domain Controllers or any other server grouping that can be queried with PowerShell or a fixed list in a text file is so desired.
# File definitions $Date = Get-Date -Format "MM.dd.yyyy-hh.mm-tt" $FreeSpaceResults = 'C:\DiskSpace\FreeSpace.csv' $FreeSpaceHTML = 'C:\DiskSpace\FreeSpace.html' $FreeSpaceSorted = 'C:\DiskSpace\FreeSpaceSorted.csv' $FreeSpaceHTMLSorted = 'C:\DiskSpace\FreeSpaceSorted.html' $ExpandedResults = 'C:\DiskSpace\DiskSpace\ExpandedSpacereport'+$Date+'.html' $LowDrivespace = 'C:\DiskSpace\LowDriveSpaceReport'+$Date+'.html' $UnderFive = @() $UnderFifteen = @() $UnderTwentyFive = @() # Header Added $Output = "<!DOCTYPE html PUBLIC `"-//W3C//DTD XHTML 1.0 Strict//EN`" `"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd`">" | Out-File $ExpandedResults $Output = "<html xmlns=`"http://www.w3.org/1999/xhtml`">" | Out-File $ExpandedResults -Append $Output = "<head>" | Out-File $ExpandedResults -Append $Output = "<title>HTML TABLE</title>" | Out-File $ExpandedResults -Append $Output = "</head><body>" | Out-File $ExpandedResults -Append # Get Exchange Server $Exchangeservers = (Get-ExchangeServer).Name | Sort Name # Freespace results File header $Export = 'Name,FreeSpace,DriveSize,PercentFree' | Out-file $FreeSpaceresults # Loop Foreach ($ExchangeServer in $Exchangeservers) { # Clear variables $CSV = $Null $Export = $null # Table and Table Headers $Output = "<table>" | Out-File $ExpandedResults -Append $Output = "<h2>$ExchangeServer</h2>" | Out-File $ExpandedResults -Append $Output = '<colgroup><col/><col/><col/><col/></colgroup>' | Out-File $ExpandedResults -Append $Output = "<tr><b><td>Name</td><td>FreeSpace</td><td>DriveSize</td><td>PercentFree</td></b></tr>" | Out-File $ExpandedResults -Append # Get Volumes $Volumes = Get-Volume -CimSession $ExchangeServer | Sort FileSystemLabel # Add lines to file Foreach ($Volume in $Volumes) { $Size = ($Volume.Size)/1GB $SizeRemaining = ($Volume.SizeRemaining)/1GB $PercentFree = [Math]::Round($($SizeRemaining/$Size),4) $Name=$Volume.FileSystemLabel $SizeR = [Math]::Round(($Volume.Size)/1GB,2) $SizeRemainingR = [Math]::Round(($Volume.SizeRemaining)/1GB,2) $P = $PercentFree.toString('p') $Export += "$Name,$SizeRemainingR,$SizeR,$P" | Out-File $FreeSpaceResults -Append If ($PercentFree -lt 0.05) { # Write-Host "$ExchangeServer,$Name,$SizeRemainingR,$SizeR,$P" -Foreground Red # $UnderFive += "$ExchangeServer,$Name,$SizeRemainingR,$SizeR,$P" $Under5 = $True $Obj = New-Object PSObject $Obj | Add-Member -MemberType NoteProperty -Name "ExchangeServer" -Value $ExchangeServer $Obj | Add-Member -MemberType NoteProperty -Name "Volume" -Value $Name $Obj | Add-Member -MemberType NoteProperty -Name "FreeSpace" -Value $SizeRemainingR $Obj | Add-Member -MemberType NoteProperty -Name "driveSpace" -Value $SizeR $Obj | Add-Member -MemberType NoteProperty -Name "PercentFree" -Value $P $UnderFive += $Obj } If (($PercentFree -gt 0.05) -and ($PercentFree -le 0.15)) { # Write-Host "$ExchangeServer,$Name,$SizeRemainingR,$SizeR,$P" -Foreground Yellow # $UnderFifteen += "$ExchangeServer,$Name,$SizeRemainingR,$SizeR,$P" $Under15 = $True $Obj = New-Object PSObject $Obj | Add-Member -MemberType NoteProperty -Name "ExchangeServer" -Value $ExchangeServer $Obj | Add-Member -MemberType NoteProperty -Name "Volume" -Value $Name $Obj | Add-Member -MemberType NoteProperty -Name "FreeSpace" -Value $SizeRemainingR $Obj | Add-Member -MemberType NoteProperty -Name "driveSpace" -Value $SizeR $Obj | Add-Member -MemberType NoteProperty -Name "PercentFree" -Value $P $UnderFifteen += $Obj } If (($PercentFree -gt 0.15) -and ($PercentFree -lt 0.25)) { # Write-Host "$ExchangeServer,$Name,$SizeRemainingR,$SizeR,$P" -Foreground Magenta # $UnderTwentyFive += "$ExchangeServer,$Name,$SizeRemainingR,$SizeR,$P" $Under25 = $True $Obj = New-Object PSObject $Obj | Add-Member -MemberType NoteProperty -Name "ExchangeServer" -Value $ExchangeServer $Obj | Add-Member -MemberType NoteProperty -Name "Volume" -Value $Name $Obj | Add-Member -MemberType NoteProperty -Name "FreeSpace" -Value $SizeRemainingR $Obj | Add-Member -MemberType NoteProperty -Name "driveSpace" -Value $SizeR $Obj | Add-Member -MemberType NoteProperty -Name "PercentFree" -Value $P $UnderTwentyFive += $Obj } } # Report 1 $CSV = Import-CSV $FreeSpaceResults $FreeSpaceSorted = $CSV | sort 'PercentFree' Foreach ($Line in $FreeSpaceSorted) { $Value1 = $Line.Name $Value2 = $Line.FreeSpace $Value3 = $Line.DriveSize $Value4 = $Line.PercentFree $Output = "<tr><td>$Value1</td><td>$Value2</td><td>$Value3</td><td>$Value4</td></tr>" | Out-File $ExpandedResults -Append } # End the current Table $Output = '</table>' | Out-File $ExpandedResults -Append $Output = '' | Out-File $ExpandedResults -Append # Stop the Loop } # End the File $Output = '</body></html>' | Out-File $ExpandedResults -Append # Low Space report $Output2 = "<!DOCTYPE html PUBLIC `"-//W3C//DTD XHTML 1.0 Strict//EN`" `"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd`">" | Out-File $LowDrivespace $Output2 = "<html xmlns=`"http://www.w3.org/1999/xhtml`">" | Out-File $LowDrivespace -Append $Output2 = "<head>" | Out-File $LowDrivespace -Append $Output2 = "<title>HTML TABLE</title>" | Out-File $LowDrivespace -Append $Output2 = "</head><body>" | Out-File $LowDrivespace -Append $Output = "<table>" | Out-File $LowDrivespace -Append $Output = "<h2>Volumes with Low Disk Space</h2>" | Out-File $LowDrivespace -Append # Section 1 $UnderFiveSorted = $UnderFive | sort 'PercentFree' $Output = "<table>" | Out-File $LowDrivespace -Append $Output = "<h2>Under 5 % Free</h2>" | Out-File $LowDrivespace -Append If ($Under5) { $Output = '<colgroup><col/><col/><col/><col/></colgroup>' | Out-File $ExpandedResults -Append $Output = "<tr><b><td>ExchangeServer</td><td>Volume</td><td>FreeSpace</td><td>DriveSize</td><td>PercentFree</td></b></tr>" | Out-File $LowDrivespace -Append Foreach ($Line in $UnderFiveSorted) { $Value0 = $Line.ExchangeServer $Value1 = $Line.Volume $Value2 = $Line.FreeSpace $Value3 = $Line.DriveSpace $Value4 = $Line.PercentFree $Output = "<tr><td>$Value0</td><td>$Value1</td><td>$Value2</td><td>$Value3</td><td>$Value4</td></tr>" | Out-File $LowDrivespace -Append } # End the current Table $Output = '</table>' | Out-File $LowDrivespace -Append $Output = '' | Out-File $LowDrivespace -Append } Else { # Empty Table $Output = "<tr><td>No servers have drives under 5% free space.</td></tr>" | Out-File $LowDrivespace -Append # End the current Table $Output = '</table>' | Out-File $LowDrivespace -Append $Output = '' | Out-File $LowDrivespace -Append } # Section 2 $UnderFifteenSorted = $UnderFifteen | sort 'PercentFree' $Output = "<table>" | Out-File $LowDrivespace -Append $Output = "<h2>Under 15 % Free</h2>" | Out-File $LowDrivespace -Append If ($Under15) { $Output = '<colgroup><col/><col/><col/><col/></colgroup>' | Out-File $LowDrivespace -Append $Output = "<tr><b><td>ExchangeServer</td><td>Volume</td><td>FreeSpace</td><td>DriveSize</td><td>PercentFree</td></b></tr>" | Out-File $LowDrivespace -Append Foreach ($Line in $UnderFifteenSorted) { $Value0 = $Line.ExchangeServer $Value1 = $Line.Volume $Value2 = $Line.FreeSpace $Value3 = $Line.DriveSpace $Value4 = $Line.PercentFree $Output = "<tr><td>$Value0</td><td>$Value1</td><td>$Value2</td><td>$Value3</td><td>$Value4</td></tr>" | Out-File $LowDrivespace -Append } # End the current Table $Output = '</table>' | Out-File $LowDrivespace -Append $Output = '' | Out-File $LowDrivespaces -Append } Else { # Empty Table $Output = "<tr><td>No servers have drives under 15% free space.</td></tr>" | Out-File $LowDrivespace -Append # End the current Table $Output = '</table>' | Out-File $LowDrivespace -Append $Output = '' | Out-File $LowDrivespace -Append } # Section 3 $UnderTwentyFiveSorted = $UnderTwentyFive | sort 'PercentFree' $Output = "<table>" | Out-File $LowDrivespace -Append $Output = "<h2>Under 25 % Free</h2>" | Out-File $LowDrivespace -Append If ($Under25) { $Output = '<colgroup><col/><col/><col/><col/></colgroup>' | Out-File $LowDrivespace -Append $Output = "<tr><b><td>ExchangeServer</td><td>Volume</td><td>FreeSpace</td><td>DriveSize</td><td>PercentFree</td></b></tr>" | Out-File $LowDrivespace -Append Foreach ($Line in $UnderTwentyFiveSorted) { $Value0 = $Line.ExchangeServer $Value1 = $Line.Volume $Value2 = $Line.FreeSpace $Value3 = $Line.DriveSpace $Value4 = $Line.PercentFree $Output = "<tr><td>$Value0</td><td>$Value1</td><td>$Value2</td><td>$Value3</td><td>$Value4</td></tr>" | Out-File $LowDrivespace -Append } # End the current Table $Output = '</table>' | Out-File $LowDrivespace -Append $Output = '' | Out-File $LowDrivespace -Append } Else { # Empty Table $Output = "<tr><td>No servers have drives under 25% free space.</td></tr>" | Out-File $LowDrivespace -Append # End the current Table $Output = '</table>' | Out-File $LowDrivespace -Append $Output = '' | Out-File $LowDrivespace -Append } $Output = '</body></html>' | Out-File $LowDrivespace -Append # Send email $To = 'damian.scoles@powershellgeek.com' $From = 'notifications@powershellgeek.com' $Subject = 'Exchange Disk Space Monitoring Reports' $File = Import-CSV $LowDriveSpace $Body = @() Foreach ($Line in $File) {$Body+=$Line} $SMTPServer = 'smtpserver.domain.com' Send-MailMessage -To $To -From $From -Subject $Subject -Body ($Body | Out-String) -BodyAsHtml -SmtpServer $SMTPServer # Close PowerShell session off Get-PSSession | Remove-PSSession
Sample Report
Conclusion
While on-premises servers are not as hot a topic as they were 10 years ago they still play an important role in an organizations infrastructure. As such they should be monitored and maintained until they are replaced or moved to a cloud service. Even in the cloud some monitoring may still be necessary to maintain an environment. At the very least these scripts will help a new or existing admin understand their system better and keep an eye on certain aspects of their lifecycle. None of these scripts are comprehensive and should be used as building blocks for a more in-depth monitoring system.