Expert Commentary: 2012 Scripting Games Advanced Event 4

Expert Commentary: 2012 Scripting Games Advanced Event 4

  • Comments 5
  • Likes

Summary: Microsoft MVP, Chad Miller, provides expert commentary for 2012 Scripting Games Advanced Event 4.

Microsoft Scripting Guy, Ed Wilson, is here. Chad Miller is the expert commentator for Advanced Event 4.

Chad is a senior manager of database administration at Raymond James Financial. Chad has worked with Microsoft SQL Server since 1999, and he has been automating administration tasks by using Windows PowerShell since 2007. Chad is a Windows PowerShell MVP and the project coordinator and developer of the Windows PowerShell-based CodePlex project, SQL Server PowerShell Extensions (SQLPSX). Chad leads the Tampa PowerShell User Group, and he is a frequent speaker at users groups, SQL Saturdays, and Code Camps.

Blog: Sev17—SQL Server, PowerShell, and so on
Twitter: @cmille19

The function Get-FolderSize reports the folder size of the specified folder and all subfolders. A path (folder) must be provided to the Get-FolderSize function.

To display the folder size for the current directory, use:

Get-FolderSize

Image of command output

To display folder size information for a list of folders, use:

Get-FolderSize Desktop,Downloads,DropBox

or

Get-Content folders.txt | Get-FolderSize

The code for this script is shown here:

#######################

<#

.SYNOPSIS

Gets folder size.

.DESCRIPTION

The Get-FolderSize function gets the folder size at the specified location.

.EXAMPLE

Get-FolderSize .

This command gets the folder size of the current directory. The dot (.) represents the item at the current location.

.EXAMPLE

Get-FolderSize C:\Windows

This command the folder size of the Windows directory.

.INPUTS

    System.String

        You can pipe a string that contains a path to Get-FolderSize.

.OUTPUTS

    Selected.System.Management.Automation.PSCustomObject

.NOTES

Version History

v1.0   - Chad Miller - Initial release

#>

function Get-FolderSize

{

    [CmdletBinding()]

    param(

    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]

    [ValidateNotNullorEmpty()]

    [string[]]$Path

    )

    BEGIN {

        function Format-FolderSize

        {

            param($Size)

 

            if ($Size -ge 1GB) {

                "{0:N2} Gigabytes" -f $($Size/1GB)

            }

            elseif ($Size -ge 1MB) {

                "{0:N2} Megabytes" -f $($Size/1MB)

            }

            else {

                "{0:N2} Bytes" -f $Size

            }

 

        } #Format-FolderSize

    }

    PROCESS {

        Get-Item $Path |  Foreach-Object {$_; $_ | Get-Childitem -Recurse} |

        Where-Object {$_.PSIsContainer}  |

        Select-Object FullName, @{name='Size';expression={$(Get-ChildItem $_.FullName -Recurse | Measure-Object -Sum -Property Length).Sum}} |

        Sort-Object Size -Descending |

        Select-Object @{name="Folder";expression={$_.FullName}}, @{name='Size of Folder';expression={$(Format-FolderSize -Size $_.Size)}}

    }

    END {}

 

 

} #Get-FolderSize

The main section of script is shown here:

The approach I took to solve this problem follows the structures of the PROCESS block of the script. I would start with step one and proceed to the next steps only when the results from the previous steps have been achieved.

  1. Use the Get-Item cmdlet to retrieve information about the specified path. The ForEach-Object cmdlet returns the item, and Get-ChildItem is called recursively to retrieve all child items.
  2. Apply a filter using Where-Object, which tests whether the PSIsContainer property is true, which means the item is of type directory.
  3. After we have the specified directory and all subdirectories, use select-object to retrieve the FullName property, and add a Size property by using a hash table with name and expression keys. The expression uses the Measure-Object cmdlet, summing on the Length property.
  4. Now sort the object by the newly added Size property.
  5. Finally, use the Select-Object cmdlet to emit a custom object with Folder and Size of Folder properties. The Size of Folder property makes use of the function Format-FolderSize, which is defined in the BEGIN block of Get-FolderSize. The Format-FolderSize handles formatting the folder size in the appropriate unit of measurement (gigabytes, megabytes, or bytes). By defining the Format-Folder function in the BEGIN block, the function is private and not visible outside of the Get-FolderSize function.

~Chad

The 2012 Scripting Games Guest Commentator Week will continue tomorrow when we will present the scenario for Event 5.

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 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • I went a  different way on this one.

    $DirCounts = @{}

    get-childitem $Directory -Recurse |

      where {-not ($_.psiscontainer)} |

          select directoryname,length |

           foreach-object {

            $DirPath = $_.directoryname

              While ($DirPath -ge $Directory){

                  $DirCounts.$DirPath += $_.length

                  $DirPath = $DirPath | Split-Path -Parent

                  }

           }

    $dircounts.getenumerator() | sort value -Descending

    While admittedly a little unconventional, it has the advantage of only requiring one directory read operation. That could mean a substantial performace advantage depending on how extensive the directory structure is that you're reporting on.

  • @mjolinor: Wouldn't the below have been easier instead of foreach? Or, am I missing something?

    Get-ChildItem $Directory -Recurse |

       Where-Object {-not ($_.psiscontainer)} |

           Group-Object -Property DirectoryName|

               Select-Object Name, @{Name="DirSize";Expression={ (($_.Group|Measure-Object -Property Length -Sum).Sum/1MB)} } |

    Sort-Object -Property DirSize -Descending | Select -First 3 | Format-Table -AutoSize

    Name DirSize

    ---- -------

    C:\Hemanth-SQLServer\Outlook-PST 615.2009392

    C:\Hemanth-SQLServer\Data_From_Old_Laptop 510.4251547

    C:\Hemanth-SQLServer\MSSQL\BOL 281.6665039

  • @Hemanth I believe that will report on the size of the files in each directory. If I'm reading the event criteria correctly, they want the size of the files in each directory and all of it's subdirectories.  That means that for any given file it's length must be attributed to not just it's immediate directory, but every parent directory in it's directory path, back to the base directory that's being reported on.

  • @Rob,

    So, something like this would work?

    Get-ChildItem $Directory -Recurse |

    Where-Object {-not ($_.psiscontainer)} |

    Group-Object -Property DirectoryName|

    Select-Object Name, @{Name="DirSize";Expression={ (($_.Group|Measure-Object -Property Length -Sum).Sum)} } |

    Group-Object -Property Name | Select-Object Name, @{Name="DirSizes";Expression={(($_.Group|Measure-Object -Property DirSize -Sum).Sum)}} |

    Sort-Object -Property Name | Select -First 10 | Format-Table -AutoSize

    Name                                                                  DirSizes

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

    C:\Hemanth-SQLServer                                                  20046514

    C:\Hemanth-SQLServer\2012SG                                             632674

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_2               24942

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_2\otherssols     1790

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_3\otherssols     2641

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_4                4611

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_4\otherssols     2720

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_5                8374

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_5\otherssols    10454

    C:\Hemanth-SQLServer\2012SG\AdvancedEvents\AdvancedEvent_6                4980

  • @Hermanth - I ran both of them against a test directory and got different rusults.

    It look like that misses any directory that only has subdirectories in it.