Learn about Windows PowerShell
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
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.
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.
~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
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?
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.