Use PowerShell to Create a Report Displaying Free Disk Space

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to create a report that displays free disk space on servers.

Hey, Scripting Guy! Question Hey, Scripting Guy! I know it may be hard to believe in today’s era of multiterabyte disks on laptops, but our servers are constantly running out of disk space. Part of the problem is that they were built several years ago, and with all of the patches, service packs, software installed and uninstalled, registry bloat, and whatever else, we are constantly running out of disk space. We are a small shop, and we do not have a network monitoring program such as System Center. What we do have is a CIO who has no clues about how computers work, and who goes herbitile when any server is down for even five seconds, not to mention when a server is down for a couple of days and we have to order a new drive and restore things from tape to rebuild the system drive. I need something that will produce a daily report letting me know the amount of free disk space on each of the drives. Can you help me out? I have seen some scripts on the Script Repository, but nothing that creates a very nice report.


Hey, Scripting Guy! Answer Hello DV,

Microsoft Scripting Guy, Ed Wilson, is here. Today it is cool down here in Charlotte, North Carolina in the southern portion of the United States. It is because the skies are cloudy and it is threatening thunder storms. But hey, it is cooler than it has been in a week, so we will accept any temperature relief offered.

DV, because it is a nice cool day down here, I am going to cheat a bit and use the report and the same basic script I wrote yesterday. What I will do is add free disk space to the report—that should work for you.

First find the information

Note   This is the second blog in a series that discusses creating an HTML report that contains server status information. You should read yesterday’s blog, Use PowerShell to Create an HTML Uptime Report, prior to reading today’s.

The WMI class Win32_Volume (in the operating system since Windows Server 2003) contains a property named freespace. Unfortunately, this property displays in bytes, which means that the numbers are rather large and difficult to comprehend. A generic query to Win32_Volume returns the CD-ROM drive, mapped network drives, and other things you may not be interested in receiving. However, a drive type of 3 is a fixed local disk, and it is the information you want to receive. To fix the output requires a couple of things. First, it requires converting the free space from bytes to gigabytes. To do this, I divide by the GB admin constant. I add it to a custom object, and I create a custom label. This technique is shown here.

PS C:\> gwmi win32_volume -Filter 'drivetype = 3' | select driveletter, label, @{LABE

L='GBfreespace';EXPRESSION={$_.freespace/1GB} }


driveletter                  label                                       GBfreespace

-----------                  -----                                       -----------

                             System Reserved                       0.106239318847656

C:                                                                  60.1407623291016

Unfortunately, the output is still a bit difficult to read due to the great amount of precision following the decimal. I now use a format specifier to change the way the numbers display. This is shown here.

PS C:\> gwmi win32_volume -Filter 'drivetype = 3' |

select driveletter, label, @{LABEL='GBfreespace';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)} }


driveletter                  label                       GBfreespace

-----------                  -----                       -----------

                             System Reserved             0.11

C:                                                       60.14

Break up the report

Unfortunately, I cannot just add the disk information as an additional property on the custom object and have it unravel onto the report. This is because all the servers have multiple drives, and I therefore end up with an array of disk objects that I must report. The solution is to break-up the report a bit, and report the information in fragments. Therefore, I go back to my code from yesterday, and modify it just a little so that instead of writing directly to the report, I create a fragment and store the returned fragment in a variable. Also note that you cannot use the fragment and the body parameters together. I decide to change the report title from <h1> to <h2> because I am going to use a different report heading. <h2> as you might imagine is a bit smaller than <h1>.

$upTime = Get-UpTime -servers $servers |

ConvertTo-Html -As Table -Fragment -PreContent "

  <h2>Server Uptime Report</h2>

  The following report was run on $(get-date)" | Out-String

Add the new function and call the function

I now create a function to gather the disk space information. The function contains the essential code that I created at the Windows PowerShell console, but wrapped as a function. 

Function Get-DiskSpace


 Param ([string[]]$servers)

  Foreach ($s in $servers)


     Get-WmiObject -Class win32_volume -cn $s |

       Select-Object @{LABEL='Comptuer';EXPRESSION={$s}},

         driveletter, label,

         @{LABEL='GBfreespace';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)}}

    } #end foreach $s

} #end function Get-DiskSpace

I copy the same essential code that I used to create the Uptime fragment to create the disk space fragment. I use the <h2> tag as a table header to let me know which section of the report appears.

$disk = Get-DiskSpace -servers $servers |

ConvertTo-Html -As Table -Fragment -PreContent "

  <h2>Disk Report</h2> "| Out-String   

Create the new report

Now I need to create the report. First, I add precontent. This content appears at the top of the report. I use the same type of <h1> tag that I used yesterday for the report title. Now the post content consists of the two HTML fragments that I created via the two functions. Instead of converting the entire thing to a string, I write it out to the file, and then I use the Invoke-Item cmdlet to launch the report. This code is shown here.

$disk = Get-DiskSpace -servers $servers |

ConvertTo-Html -As Table -Fragment -PreContent "

  <h2>Disk Report</h2> "| Out-String 


ConvertTo-Html -PreContent "<h1>Server Uptime and Disk Report</h1>" `

  -PostContent $upTime, $disk >> $path

 Invoke-Item $path 

The completed report appears in the following image.

Image of command output

I uploaded the complete HTML_UptimeFreeSpaceReport.ps1 script to the Scripting Guys Script Repository.

DV, that is all there is to using Windows PowerShell to create an HTML free disk space report. Join me tomorrow for more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Comments (19)

  1. mredwilson says:

    @Klaus, thank you and yes ConvertTo-Html is a complicated cmdlet which is why I chose to write about it this week.

  2. mredwilson says:

    @jrv Thanks for the additional information

  3. Anonymous says:

    Thanks for Article. It is helpful.

  4. jrv says:

    The following was generated with POwerSHel using ConvertTo-Html.  It is a multitable report with style and can have dynamic coloring based on row/column values.  This version does not show that.  The colors are for clarifying the layout and not meant to be pertty.  We can have any colors we need and cal also add logos and icons very easily.

    Have a look:…/template1.htm

  5. K_Schulte says:

    Hi Ed,

    great work!

    It is a very interesting feature of the ConvertTo-Html cmdlet that makes it possible to create a table from fragments like this. Of course the precontent switch is not self-explanatory. I think we have to experiment a little bit more with this cmdlet …


  6. Hi!

    Great and interesting article!


  7. mredwilson says:

    @Marius Thank you glad you enjoyed the article.

  8. Great stuff! I wrote a similar script that takes a text file input for multiple servers. The script also reports on servers with less than or equal to 10% disk space. Finally, it emails a CSV report to you. See blog here: I have another blog that details how you can schedule a powershell script to run using Windows Task Scheduler –

  9. jrv says:

    @Ed  – It is good you are blogging this.  I was experimenting and adding to some code I had written a year ago to colorize multi-table reports with PowerShell.

    Her is an examplke of a report with a dynamically colorcoded table row that is colored according to its value.  Thisuis useful in email annoucments and alerts as a way of quickly showing threshold exceptions or status exceptions.  This shows only one enunciator color.  Many are possible.…/image4.png

  10. AJ says:

    Why not use Virtu-Al's html framework to generate html reports and have them emailed directly to yourself?  The framework is very easy to use and modularized.…/vcheck

    Originally written for VMWare daily reports but an Exchange 2007/2010 report has been released and someone is working on a NetApp filer report.  I have used the framework to give me a report of Active Directory users, computers, groups etc that runs on a scheduled task once a week.

  11. AJ says:

    Use the html framework (link in my last post) and this script as a plugin:

    # Set output variables

    $Date = Get-Date

    $Header = "Server Disk Space"

    $Comments = "Server Disk Space as of $Date"

    $Display = "Table"

    $Author = "<your name here>"

    $PluginVersion = 1.0

    $PluginCategory = "Active Directory"

    # Query AD for all Servers

    $rtn = $null

    $Disk = Get-ADComputer -Filter 'OperatingSystem -like "*Server*"' |

    ForEach-Object {

     #Ping all returned servers with 1 packet

     $rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet

     #If $rtn is true, then gather disk space

     IF($rtn -match 'True') {Get-WMIObject Win32_LogicalDisk -filter DriveType=3 -computer $_.dnshostname | Select SystemName,DeviceID,VolumeName,@{Name=”Total Size (GB)”;Expression={[decimal]("{0:N2}" -f($_.size/1gb))}},@{Name=”Used Space (GB)”;Expression={[decimal]("{0:N2}" -f(($_.size/1gb) – ($_.freespace/1gb)))}},@{Name=”Free Space (GB)”;Expression={[decimal]("{0:N2}" -f($_.freespace/1gb))}},@{Name=”Free Space (%)”;Expression={"{0:P2}" -f(($_.freespace/1gb) / ($_.size/1gb))}}}

     #if $rtn is false, nothing

     ELSE {  }


    # Output info to report

       $script:MyReport += Get-CustomHeader $Header $Comments

       $script:MyReport += Get-HTMLTable $Disk

       $script:MyReport += Get-CustomHeaderClose

  12. Idea says:

    Instead of trying to overcome this single issue with scripts have a look at Nagios or Nagios XI which costs to license but has a very easy user interface.  It;s open source and will give you monitoring on Disk usage, up time,ping, network  and any number of other things you may be interested.  Great product with great community.

  13. Jon Raines says:

    This is nice, but I can't help but comment about how stupid it is that PS has no simple command like df in Linux.  It's a great language and I am trying to move to using it as my default instead of DOS, but basic oversights like this are a pain.

  14. Ram Karthik says:

    Hi Ed – Great Script.

    Could you guide for a similar script to be used on exchange Servers?

  15. Jason says:

    Was having a problem with sorting the results until I found computer is spelled wrong, you have it as “comptuer”

  16. Gene says:

    This was helpful..

  17. Faruqu says:

    Try using following PS

    $hostname = Read-Host "Enter Computer Name"

    Get-WmiObject -Class Win32_LogicalDisk -Filter "drivetype=3" -computer $hostname | Select-Object DeviceID,VolumeName,Size,FreeSpace,FileSystem | Select @{Name="Drive";Expression={$_.DeviceID}},

    @{Name="Size GB";Expression={$_.Size/1GB -as [int]}},
    @{Name="Used GB";Expression={"{0:N2}" -f (($_.Size – $_.Freespace)/1GB) }},
    @{Name="Free GB";Expression={"{0:N2}" -f ($_.FreeSpace/1GB) }

  18. Scott Wilkinson says:

    Thanks Faruqu, that removes the pesky Optical Drive from the list of drives. Why would anyone care about the free space on that? Your example is missing a trailing ‘}’ brace though.
    Minor typo "Comptuer" in the main example code also.

  19. Shankar says:

    Hi Ed,
    How can I find the disk space utilized,disk space available in individual partitions in terms of memory(bytes) and percentage?

Skip to main content