Difficulty: Intermediate

This guide will teach you how to take a powershell script, turn it into a scheduled task, and have the output of the script be emailed to you. The script I’m going to be demoing here is a simple disk space check that runs on a list of servers you define. For every server in the list with a drive that has less than 20% of storage left, the server host name, drive letter, and amount of disk space left will be displayed.

Before we begin working with the script, we must first prepare our server for powershell. Windows 2008 Server may already have powershell preinstalled. If it is, you will be able to find it in START > Accessories > Windows Powershell. If it is not there, then you will have to install it by going into control panel, programs and features, and turn windows features on or off, and enabling Windows Powershell.

Disk Space Report
Source: http://gallery.technet.microsoft.com/scriptcenter/Disk-Space-Report-Reports-98e64d65

Copy the following script and paste it in notepad on your server. Save the file as a “All type” and name it diskspacereport.ps1

Save this file somewhere that you will remember where it is. For me, I saved it in a new folder I created on the Server’s C: drive. (Ex: C:powershelldiskspacereport)

You will need to edit this file with notepad to make changes to the script. The text marked in red is where you will be plugging in information that pertains to your environment. I have broken the script down even more below to show you just how all of the variables work.

#############################################################################
# #
# Check disk space and send an HTML report as the body of an email. #
# Reports only disks on computers that have low disk space. #
# Author: Mike Carmody #
# Some ideas extracted from Thiyagu’s Exchange DiskspaceHTMLReport module. #
# Date: 8/10/2011 #
# I have not added any error checking into this script yet. #
# #
# #
#############################################################################
# Continue even if there are errors
$ErrorActionPreference = “Continue”;

#########################################################################################
# Items to change to make it work for you.
#
# EMAIL PROPERTIES
# – the $users that this report will be sent to.
# – near the end of the script the smtpserver, From and Subject.

# REPORT PROPERTIES
# – you can edit the report path and report name of the html file that is the report.
#########################################################################################

# Set your warning and critical thresholds
$percentWarning = 15;
$percentCritcal = 10;

# EMAIL PROPERTIES
# Set the recipients of the report.
$users = “EMAILTO@COMPANY.COM
# Below commented out are some examples of how this report can be emailed

#$users = “You@company.com” # I use this for testing by using my email address.
#$users = “you@company.com”, “manager@company.com”, “etc@company.com”; # can be sent to individuals.

# REPORT PROPERTIES
# Path to the report
# The server hosting my report is also a web server. You will notice that I placed the script output in the wwwroot. This can go anywhere you like.
$reportPath = “\WEBSERVERC$inetpubwwwrootWEB_DIRECTORYindex.html”;
# Report name
$reportName = “index.html”;

# Path and Report name together
$diskReport = $reportPath + $reportName

#Set colors for table cell backgrounds
$redColor = “#FF0000″
$orangeColor = “#FBB917″
$whiteColor = “#FFFFFF”

# Count if any computers have low disk space. Do not send report if less than 1.
$i = 0;

# Get computer list to check disk space
# The report gathers the servers from a plain text file stored on my network
$computers = Get-Content “H:~PROJECTSReportsServersservers.txt“;
$datetime = Get-Date -Format “MM-dd-yyyy_HHmmss”;

# Remove the report if it has already been run today so it does not append to the existing report
If (Test-Path $diskReport)
{
Remove-Item $diskReport
}

# Cleanup old files..
$Daysback = “-7″
$CurrentDate = Get-Date;
$DateToDelete = $CurrentDate.AddDays($Daysback);
Get-ChildItem $reportPath | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item;

# Create and write HTML Header of report
$titleDate = get-date -uformat “%m-%d-%Y – %A”
$header = ”
<html>
<head>
<meta http-equiv=’Content-Type’ content=’text/html; charset=iso-8859-1′>
<title>DiskSpace Report</title>
<STYLE TYPE=’text/css’>
<!–
td {
font-family: Tahoma;
font-size: 11px;
border-top: 1px solid #999999;
border-right: 1px solid #999999;
border-bottom: 1px solid #999999;
border-left: 1px solid #999999;
padding-top: 0px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px;
}
body {
margin-left: 5px;
margin-top: 5px;
margin-right: 0px;
margin-bottom: 10px;
table {
border: thin solid #000000;
}
–>
</style>
</head>
<body>
<table width=’100%’>
<tr bgcolor=’#CCCCCC’>
<td colspan=’7′ height=’25’ align=’center’>
<font face=’tahoma’ color=’#003399′ size=’4′><strong>DiskSpace Report for $titledate</strong></font>
</td>
</tr>
</table>

Add-Content $diskReport $header

# Create and write Table header for report
$tableHeader = ”
<table width=’100%’><tbody>
<tr bgcolor=#CCCCCC>
<td width=’10%’ align=’center’>Server</td>
<td width=’5%’ align=’center’>Drive</td>
<td width=’15%’ align=’center’>Drive Label</td>
<td width=’10%’ align=’center’>Total Capacity(GB)</td>
<td width=’10%’ align=’center’>Used Capacity(GB)</td>
<td width=’10%’ align=’center’>Free Space(GB)</td>
<td width=’5%’ align=’center’>Freespace %</td>
</tr>

Add-Content $diskReport $tableHeader

# Start processing disk space reports against a list of servers
foreach($computer in $computers)
{
$disks = Get-WmiObject -ComputerName $computer -Class Win32_LogicalDisk -Filter “DriveType = 3″
$computer = $computer.toupper()
foreach($disk in $disks)
{
$deviceID = $disk.DeviceID;
$volName = $disk.VolumeName;
[float]$size = $disk.Size;
[float]$freespace = $disk.FreeSpace;
$percentFree = [Math]::Round(($freespace / $size) * 100, 2);
$sizeGB = [Math]::Round($size / 1073741824, 2);
$freeSpaceGB = [Math]::Round($freespace / 1073741824, 2);
$usedSpaceGB = $sizeGB – $freeSpaceGB;
$color = $whiteColor;

# Set background color to Orange if just a warning
if($percentFree -lt $percentWarning)
{
$color = $orangeColor

# Set background color to Orange if space is Critical
if($percentFree -lt $percentCritcal)
{
$color = $redColor
}

# Create table data rows
$dataRow = ”
<tr>
<td width=’10%’>$computer</td>
<td width=’5%’ align=’center’>$deviceID</td>
<td width=’15%’ >$volName</td>
<td width=’10%’ align=’center’>$sizeGB</td>
<td width=’10%’ align=’center’>$usedSpaceGB</td>
<td width=’10%’ align=’center’>$freeSpaceGB</td>
<td width=’5%’ bgcolor=`’$color`’ align=’center’>$percentFree</td>
</tr>

Add-Content $diskReport $dataRow;
Write-Host -ForegroundColor DarkYellow “$computer $deviceID percentage free space = $percentFree”;
$i++
}
}
}

# Create table at end of report showing legend of colors for the critical and warning
$tableDescription = ”
</table><br><table width=’20%’>
<tr bgcolor=’White’>
<td width=’10%’ align=’center’ bgcolor=’#FBB917′>Warning less than 15% free space</td>
<td width=’10%’ align=’center’ bgcolor=’#FF0000′>Critical less than 10% free space</td>
</tr>

Add-Content $diskReport $tableDescription
Add-Content $diskReport “</body></html>”

# Send Notification if alert $i is greater then 0
if ($i -gt 0)
{
foreach ($user in $users)
{
Write-Host “Sending Email notification to $user”

$smtpServer = “SMTP-SERVER.DOMAIN
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg = New-Object Net.Mail.MailMessage
$msg.To.Add($user)
$msg.From = “EMAILFROM@ADDRESS.COM
$msg.Subject = “Environment DiskSpace Report for $titledate”
$msg.IsBodyHTML = $true
$msg.Body = get-content $diskReport
$smtp.Send($msg)
$body = “Report completed.”
}
}

Now, we need to modify our script to include our email address, company name, and SMTP server information.

# EMAIL PROPERTIES
# Set the recipients of the report.
$users = “EMAILTO@COMPANY.COM
#$users = “You@company.com” # I use this for testing by uing my email address.
#$users = “you@company.com”, “manager@company.com”, “etc@company.com”; # can be sent to individuals.

This is where you choose who will receive the report in an email. You can either send it to yourself or an Active Directory Distribution Group that is tied to a shared email address.

# REPORT PROPERTIES
# Path to the report
$reportPath = “\WEBSERVERC$inetpubwwwrootWEB_DIRECTORYindex.html“;

The report also generates an HTML page, because of that I have the report being saved directory to my web server. For your server to have this directory, you will have to enable IIS.

Follow this guide on enabling IIS on Windows Server 2008: http://learn.iis.net/page.aspx/29/installing-iis-7-and-above-on-windows-server-2008-or-windows-server-2008-r2/

Once IIS has been enabled, go into the IIS manager on your server and create a new virtual web directory and map to the folder you created in wwwroot.

# Get computer list to check disk space
$computers = Get-Content “H:~PROJECTSReportsServersservers.txt“;
$datetime = Get-Date -Format “MM-dd-yyyy_HHmmss”;

To add servers which this report will be used to check, you can either add them manually here and separate them with commas or you can create a simple notepad text file with a list of your servers and point the $computers path to your file like I have done above. My servers in my notepad document are formatted like this:

SERVER1
SERVER2
SERVER3

Finally, we need to provide this report SMTP settings to relay an email message once the report completes.

$smtpServer = “SMTP-SERVER-HOSTNAME.DOMAIN
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$msg = New-Object Net.Mail.MailMessage
$msg.To.Add($user)
$msg.From = “EMAILFROM@ADDRESS.COM
$msg.Subject = “Environment DiskSpace Report for $titledate”
$msg.IsBodyHTML = $true
$msg.Body = get-content $diskReport
$smtp.Send($msg)
$body = “Report completed.”

On the server that I’m running this report, I also enabled SMTP and provided an account in which to send the email message from.

Follow this guide to enable SMTP on your server: http://www.itsolutionskb.com/2008/11/installing-and-configuring-windows-server-2008-smtp-server/

Once your powershell script has been finished with all of your settings in place, save it. It should still have that .ps1 extension for powershell.

Open a new notepad document and copy in the following line:

powershell.exe “PATH-TO-REPORTdiskspacereport.ps1″

For example, I had saved my script here: “C:powershelldiskspacereport.ps1″ so my PATH-TO-REPORT will reflect where my script is located.

Save that file as a batch file. I named my file “diskspacereport.bat”.

Now, lets schedule this task to run automatically. Go to START > Administrative Tools > Task Scheduler

Right click in the middle white space of your Task Scheduler Library and Create a New Basic Task. Here, you will need to define what this task is called, when does it occur, and what action does it do. When you get to the actions section, select Start a Program and point it to your batch file we created (diskspacereport.bat). Once complete, you can right click your newly created task and run it. After about 5 minutes, you should receive an email with the results and the HTML file should be visible if you browse to the folder or the server web page.

zv7qrnb

About The Author

28 Responses

  1. Allen Seelye

    I’m rather new to powershell. I’m getting a variety of errors when I try to run this script.

    Different version of powershell perhaps? I’m running this on Server 2008 R2.

    You must provide a value expression on the right-hand side of the '%' operator.
    At C:ScriptsDiskSpaceReportdiskspacereport.ps1:75 char:38
    + $titleDate = get-date -uformat "% <<<< m-%d-%Y-%A"
    + CategoryInfo : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : ExpectedValueExpression


    Unexpected token 'computer' in expression or statement.
    At C:ScriptsDiskSpaceReportdiskspacereport.ps1:173 char:54
    + Write-Host -ForegroundColor DarkYellow "$computer <<<< $deviceID percent
    age free space = $percentFree";
    + CategoryInfo : ParserError: (computer:String) [], ParseExceptio
    n
    + FullyQualifiedErrorId : UnexpectedToken


    Unexpected token '}' in expression or statement.
    At C:ScriptsDiskSpaceReportdiskspacereport.ps1:176 char:6
    + } <<<<
    + CategoryInfo : ParserError: (}:String) [], ParseException
    + FullyQualifiedErrorId : UnexpectedToken

  2. Chris

    Allen, I’m going to send you an updated version of this script that allows you have the results emailed to you without the part about storing the page as a website on an IIS server.

    The section of the script that I broke down for you about pulling a list of computers for the script to check against, make sure you have something like that and the Get-Content is pointing to the path of your textfile. Also, as a test you don’t have to use $Computers = Get-Conent…. you can use $Computers = “SERVER1″ with SERVER1 being the hostname of your server. The last error you received about the unexpected }, find the line in your code it’s referring to and make there is an opening bracket. If there isn’t any, then you can probably remove the close bracket.

    I recommend using something like PowerGui to help you with organizing your code and writing powershell code.

    • Mansin

      ” I’m going to send you an updated version of this script that allows you have the results emailed to you without the part about storing the page as a website on an IIS server”

      Hi Chris,

      Can you email me the same code where the report is not getting stored but being mailed directly…

      Thanks
      mansin

  3. Neil Tunnah

    Hope you can help me out please. I have had a few little problems which i have been able to sort, put this one i’m stuck on.

    Here is the error :
    Unexpected token ‘DriveType’ in expression or statement.
    diskspacereport.ps1:133 char:92

    + $disks = Get-WmiObject -ComputerName $computer -Class Win32_LogicalDisk -Filter “DriveType <<<< = 3?
    + CategoryInfo : ParserError: (DriveType:String) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

    Any ideas would be apprecitated.

    Thanks
    Neil

  4. Neil Tunnah

    After fixing the above error its now stopped at :
    170 Add-Content $diskReport $dataRow;
    171 Write-Host -ForegroundColor DarkYellow “$computer $deviceID percentage free space = $percentFree”;

    With the error :
    Unexpected token ‘computer’ in expression or statement.
    At C:diskspacereport.ps1:171 char:51
    + Write-Host -ForegroundColor DarkYellow “$computer <<<< $deviceID percentage free space = $percentFree”;
    + CategoryInfo : ParserError: (computer:String) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

    Any explanation to what is wrong will be very appreciated…

    Thanks

    • Chris

      Neil, are you supplying a variable for $computers = ? In the code I have above, I have $computers = get-content “path-to-textfile.txt” because I prepared a text file with a list of servers the report will run against. You can also do something like this $computers = “server1″,”server2″,”server3″ if you’re just going to run it against a few servers. Also, this script can only work against Windows machines as powershell is Microsoft. Let me know if this does the trick!

  5. Andre

    I have similar issues as Allen does. When I try to paste in the PS errors to this form and hit post comment, ‘the page you are looking for cannot be found’. I guess maybe there is too much text, I will send the error in two posts (or more :) )

    You must provide a value expression on the right-hand side of the ‘%’ operator.
    At line:74 char:34

    Unexpected token ‘m-%d-%Y’ in expression or statement.
    At line:74 char:35

    Unexpected token ‘-‘ in expression or statement.
    At line:74 char:43

    Unexpected token ‘%’ in expression or statement.
    At line:74 char:45

    Unexpected token ‘A”
    $header = “‘ in expression or statement.
    At line:74 char:46

    Unexpected token ‘computer’ in expression or statement.
    At line:172 char:42

    Unexpected token ‘deviceID’ in expression or statement.
    At line:172 char:52

    Unexpected token ‘percentage’ in expression or statement.
    At line:172 char:62

    Unexpected token ‘free’ in expression or statement.
    At line:172 char:73

    Unexpected token ‘space’ in expression or statement.
    At line:172 char:78

  6. Andre

    Unexpected token ‘mysmtpserver”
    $smtp = New-Object Net.Mail.SmtpClient($smtpServer)
    $msg = New-Object Net.Mail.MailMessage
    $msg.To.Add($user)
    $msg.From = “me@mydomain.com”
    $msg.Subject = “Environment’ in expression or statement.
    At line:196 char:16

    Unexpected token ‘DiskSpace’ in expression or statement.
    At line:201 char:30

    Unexpected token ‘Report’ in expression or statement.
    At line:201 char:40

    Unexpected token ‘for’ in expression or statement.
    At line:201 char:47

    Unexpected token ‘titledate’ in expression or statement.
    At line:201 char:51

  7. Andre

    Unexpected token ‘
    $msg.IsBodyHTML = $true
    $msg.Body = get-content $diskReport
    $smtp.Send($msg)
    $body = ‘ in expression or statement.
    At line:201 char:61

    Unexpected token ‘Report’ in expression or statement.
    At line:205 char:11

    The string starting:
    At line:205 char:28
    + $body = “Report completed. <<< any help would be appreciated!

  8. Chris

    Andre,

    Try using this version of the script. https://dl.dropbox.com/u/22871724/diskspacereport.zip I’ve toned down some of the features and incorporated an Active Directory search for servers rather than pulling from a text file. That way, you won’t ever have to update the text file whenever servers are added or removed. On the PC that you will running the script, I recommend installing PowerGUI and the Quest Active Directory powerpack.

    Thanks,
    Chris

  9. jrp

    Fantastic script Chris.

    One question – what does the script rely on at the server it is reporting on – when I run it in my environment it only reports on the diskpace on about 40% of the servers. I have about 20 Win2008R2 and 5 Win2003 servers.

    • Chris

      jrp, it only reports back the diskspace of the servers that meet the specified threshold of diskspace left (15% I believe). Here’s the section in the script where you can adjust this:

      # Set your warning and critical thresholds
      $percentWarning = 15;
      $percentCritcal = 10;

      Also, I didn’t write this script! It’s provided in the Microsoft Scriptcenter. I took it a step further by adding SMTP functionality and setting it up as a scheduled task.

  10. Muppet

    Hi Chris,
    Thanks for taking the time to explain the script. I do have 1 question however.
    We have clustered file servers in our environment and at some point in time the resources have been on one node and then failed over to the second. This leaves a drive with a drive letter showing (eg f Drive) but unable to access it as the resource is on a different node. When you run this script, if picks up these ‘fake’ drives and displays a NaN (not a number). Is there anyway I can script it to ignore these entries?

    I’ll post a screenshot, hopefully it works

  11. NGUYENT

    I enclose my error when running the script.
    C:>diskspacereport.bat

    C:>powershell.exe “PATH-TO-REPORTdiskspacereport.ps1″
    The term ‘PATH-TO-REPORTdiskspacereport.ps1′ is not recognized as a cmdlet, fu
    nction, operable program, or script file. Verify the term and try again.
    At line:1 char:34
    + PATH-TO-REPORTdiskspacereport.ps1 <<<<

    • Chris

      The PATH-TO-REPORT you are trying to use needs to be the directory of where you saved the “diskspacereport.ps1″

      For example: C:scriptsdiskspacereport.ps1

      Sorry for the late reply. I’m not quite sure how I missed this and haven’t been as active here as I’d like to be.

  12. KenT

    Hello,

    tanks a lot for this kind of script !
    When I launch the script, I have nothing on the html.
    The variable $computer is : $computers = “OSIRIS” when OSIRIS is the computer name.

    Can you help me ?

  13. paul

    Hi Chris!

    Thanks for your Script,

    myhostname.com percentage free space = NaN

    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
    At C:Usersmyhostnamediskreport.ps1:132 char:24
    + $disks = Get-WmiObject <<<< -ComputerName $computer -Class Win32_LogicalDisk -Filter "DriveType = 3"
    + CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

    Firewall is stopped but still script not working.
    please tell me how to solve this.

    Thanks

    • Chris

      Paul,

      When you are running the powershell script, make sure you are running it with an admin account that has access to the needed servers on your domain. It seems like this is just a permission issue.

Leave a Reply