Hey, Scripting Guy! How Can I Determine Folder Size?

ScriptingGuy1

Hey, Scripting Guy! Question

Hey, Scripting Guy! We are getting ready for a migration, and I am trying to find an easy way to determine the size of the Documents folder. I would like to use Windows PowerShell to do this, but when I use the Get-Item cmdlet to retrieve the properties of a folder, I do not see the size. I really do not want to have to iterate through the entire folder, and add up the size of all the files just to get the folder size. Do you have a magic solution you would be willing to share?

– LM

SpacerHey, Scripting Guy! Answer

Hi LM,

I do have a magical solution, which involves eye of newt (not the politician). However, I can’t share the solution with you because of the Magician’s Oath:

“As a magician I promise never to reveal the secret of any illusion to a nonmagician, unless that one swears to uphold the Magician’s Oath in turn. I promise never to perform any illusion for any nonmagician without first practicing the effect until I can perform it well enough to maintain the illusion of magic.”

So, uh, sorry about that. Remind me to show you the hidden jar of mustard trick sometime.

What’s that? Oh, right, the script. One truly amazing feat is the way that Windows PowerShell can simplify seemingly mundane tasks. As seen in this image, folder size values are clearly displayed in Windows Explorer:

Image of folder size values in a property sheet

 

For a VBScript version of this task, you may want to refer to this article. Though the two scripts are different, they take a similar approach. Here is the script:

$DocEnum = 0x5
$shell = New-Object -ComObject shell.application
$myDocs = $shell.NameSpace($DocEnum)
$folderitem = $myDocs.self
$path = $folderitem.path
 $totalSize = Get-ChildItem -path $path -recurse -errorAction “SilentlyContinue” |
 Measure-Object -property length -sum
 IF($totalSIze.Sum -ge 1073741824)
   {
      “{0:n2}” -f  ($totalSize.sum / 1GB) + ” GigaBytes”
   }
 ELSEIF($totalSize.sum -ge 1024)
    {
      “{0:n2}” -f  ($totalSize.sum / 1MB) + ” MegaBytes”
    }
 ELSE
    {
      “{0:n2}” -f  ($totalSize.sum / 1KB) + ” KiloBytes”
    }

This script begins with assigning the hexadecimal value of 0x5 to the $docEnum variable. The number 0x5 is a magic number, but I will share its meaning with you any way (I am not really a magician, but don’t pass that around). The number 0x5 is what is called a shell special folder constant. It is documented in MSDN, but I decided to clean up the listing for you, and include the values in Table 1. The cool thing is that you can use any of the hexadecimal values from Table 1 in the script, and it will tell you the size of the folder. You do not even have to use a coded value; you can just include a path to a folder, which I will show you later. Anyway, here is the code that assigns the value 0x5 to the $DocEnum variable (you could have figured this one out yourself):

$DocEnum = 0x5

Table 1 Shell Special Folder Values

Special folder name Hexadecimal value

ALTSTARTUP

0x1d

APPDATA

0x1a

BITBUCKET

0xa

COMMONALTSTARTUP

0x1e

COMMONAPPDATA

0x23

COMMONDESKTOPDIR

0x19

COMMONFAVORITES

0x1f

COMMONPROGRAMS

0x17

COMMONSTARTMENU

0x16

COMMONSTARTUP

0x18

CONTROLS

0x3

COOKIES

0x21

DESKTOP

0x0

DESKTOPDIRECTORY

0x10

DRIVES

0x11

FAVORITES

0x6

FONTS

0x14

HISTORY

0x22

INTERNETCACHE

0x20

LOCALAPPDATA

0x1c

MYPICTURES

0x27

NETHOOD

0x13

NETWORK

0x12

PERSONAL

0x5

PRINTERS

0x4

PRINTHOOD

0x1b

PROFILE

0x28

PROGRAMFILES

0x26

PROGRAMFILESx86

0x30

PROGRAMS

0x2

RECENT

0x8

SENDTO

0x9

STARTMENU

0xb

STARTUP

0x7

SYSTEM

0x25

SYSTEMx86

0x29

TEMPLATES

0x15

WINDOWS

0x24

We now need to create an instance of the shell.application object. Actually, we do not need to do this, but I thought I would do this, because it gives us access to all those special folders in Table 1. We could have used the WshShell object as seen here:

$wshshell = New-Object -ComObject wscript.shell
$wshshell.SpecialFolders.Item(“mydocuments”)

But this method does not provide access to all the folders in Table 1. It only provides access to 18 folders. This is documented on MSDN.

The shell.application object is a COM object, and is created by using the New-Object cmdlet. We store the resulting object in the $shell variable. We then use the NameSpace method from the shell object to create a folder object that references the folder stored in the $DocEnum variable. When we have the folder object, we use the self property to refer to the specific folder, and store this in the $folderItem variable. We now query the path property and store it in the $path variable. This section of code is seen here. This code is very similar to the way we would have done things in VBScript:

$shell = New-Object -ComObject shell.application
$myDocs = $shell.NameSpace($DocEnum)
$folderitem = $myDocs.self
$path = $folderitem.path

Now we are ready to use the Get-ChildItem cmdlet to get us a listing of all the files and folders in the target path. We use the -recurse parameter to allow the command to burrow down through any child folders. The -errorAction parameter tells the script to not report any errors from this command. This will suppress any “Access denied” errors you may get when targeting folders you might now have permission to:

$totalSize = Get-ChildItem -path $path -recurse -errorAction “SilentlyContinue”

We pipeline the results of the previous Get-ChildItem cmdlet to the Measure-Object cmdlet and tell it to sum the length of each file. This is shown here:

Measure-Object -property length -sum

Now we want to translate the results into something easier to read. The result from the previous command returned GenericMeasureInfo object which has a sum property. We want to translate that value into gigabytes or megabytes, if it makes sense. To do this we use a series of if statements. If the sum is bigger than 1,073,741,824, we will translate the value into gigabytes. To do this, we divide the $totalSize.Sum value by the 1GB admin constant. We use the -f format operator to display only two decimal places. This is seen here:

IF($totalSIze.Sum -ge 1073741824)
   {
      “{0:n2}” -f  ($totalSize.sum / 1GB) + ” GigaBytes”
   }

If the size is bigger than 1,024, we will display the value in megabytes (MB). We use the ELSEIF statement to get to this section of thecode:

ELSEIF($totalSize.sum -ge 1024)
    {
      “{0:n2}” -f  ($totalSize.sum / 1MB) + ” MegaBytes”
    }

However, if the size is less than 1,024, we display the value in kilobytes ((KB):

ELSE
    {
      “{0:n2}” -f  ($totalSize.sum / 1KB) + ” KiloBytes”
    }

When we run the script, the folder size is returned:

Image of the folder size as returned by the script

 

So, LM, I hope this investigation into folder size magic does not cause me to lose my magician’s union membership (Local 42), but I just had to share this trick with you. David Blaine says hi.

Ed Wilson and Craig Liebendorfer, Scripting Guys

0 comments

Discussion is closed.

Feedback usabilla icon