August 3rd, 2013

Weekend Scripter: Use PowerShell to Get Folder Sizes

Doctor Scripto
Scripter

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to get folder sizes.

Microsoft Scripting Guy, Ed Wilson, is here. I was talking via Lync to my friend Rolf in Munich, Germany the other day. He said the temperatures were approaching 100 degrees Fahrenheit. We have been lucky in Charlotte, North Carolina—we have not made it out of the 90s yet. Still, anything over 80 degrees Fahrenheit is hot in my mind. Oh well, every year it is the same down here. August rolls around, and the mercury rises.

In much the same way, certain Windows PowerShell questions keep coming around. Not exactly on a calendar type of schedule, but they do crop up again and again. These predictable questions are due to the fact that no great solution exists for the issue.

A perfect case-in-point is the issue of determining folder sizes. There is no Get-FolderSize cmdlet, and Get-ChildItem does not return a folder size on the DirectoryInfo object. For the same reason that Windows Explorer is slow when showing folder size information, there is no direct way of obtaining the information. It is not cached anywhere, and therefore, it must be calculated.

In previous Hey, Scripting Guy! Blog posts, I have enumerated all files in a folder, and returned the folder size information. I have also used the FileSystemObject. Today, I want to create a simple function that accepts pipelined input. This may prove useful for you.

The Scripting.FileSystemObject returns a folder size

One way to avoid enumerating files and adding up their sizes is to use a method that returns a folder size directly. This is where using the old-fashioned FileSystemObject comes into play. The reason I decided to create the function to accept pipelined input is so that I could use it directly from the command line. Here is the function:

Function Get-FolderSize

{

 BEGIN{$fso = New-Object -comobject Scripting.FileSystemObject}

 PROCESS{

    $path = $input.fullname

    $folder = $fso.GetFolder($path)

    $size = $folder.size

    [PSCustomObject]@{‘Name’ = $path;’Size’ = ($size / 1gb) } } }

The first thing I did was create an instance of Scripting.FileSystemObject. I only need to do this one time, and so I place it in the BEGIN block.

In the PROCESS block, I will process the pipelined input. The path comes from the pipeline input from the Get-ChildItem cmdlet. I select the FullName property because it provides the complete path to the folder. Now, I use the GetFolder method to return a folder object. The folder object has a Size property, and I store that in the $size variable. Now I create a custom object and return the folder name and size in gigabytes. That is all there is to the script.

Using the function

First I run the function in the ISE. This loads the function into memory.

If I do not run the function with Admin rights, I will not have access to all folders, and errors arise. In fact, even if I do run the function with Admin rights, it is likely I will run into errors. So I use the ErrorAction parameter (EA) and set it to SilentlyContinue (0). I then sort by size. The command is shown here:

Get-ChildItem -Directory -Recurse -EA 0 | Get-FolderSize | sort size -Descending

The command and associated output are shown in the following image:

Image of command output

So how long does it take? I use the Measure-Command to see:

Measure-command {gci -Directory -Recurse -EA 0 | Get-FolderSize | sort size -Descending }

And following are the results. A little over 30 seconds to process my entire hard drive. Not too bad, really.

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 30

Milliseconds      : 24

Ticks             : 300247135

TotalDays         : 0.000347508258101852

TotalHours        : 0.00834019819444444

TotalMinutes      : 0.500411891666667

TotalSeconds      : 30.0247135

TotalMilliseconds : 30024.7135

So where is the time spent? Is it getting the Directory listing? Let’s see…

The Directory listing only takes 5 and a half seconds as shown here:

PS C:\> Measure-command {gci -Directory -Recurse -EA 0}

 

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 8

Milliseconds      : 547

Ticks             : 85470865

TotalDays         : 9.89246122685185E-05

TotalHours        : 0.00237419069444444

TotalMinutes      : 0.142451441666667

TotalSeconds      : 8.5470865

TotalMilliseconds : 8547.0865

Well, what about sorting? How long does that take? To figure out how long the sorting takes, I run the command without the Sort-Object command. I can then see the difference between the first command and the second. Without the sort, it takes a little over 29 seconds:

PS C:\> Measure-command {gci -Directory -Recurse -EA 0 | Get-FolderSize}

 

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 29

Milliseconds      : 154

Ticks             : 291541682

TotalDays         : 0.000337432502314815

TotalHours        : 0.00809838005555556

TotalMinutes      : 0.485902803333333

TotalSeconds      : 29.1541682

TotalMilliseconds : 29154.1682

With the sort, it took a little over 30 seconds. So surprisingly enough, the sort only took about a second. So, most of the time, nearly 21 seconds, was spent in making the calculation to find the folder sizes.

Join me tomorrow for more cool Windows PowerShell stuff. Hope you have a great weekend.

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

Ed Wilson, Microsoft Scripting Guy

 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.