I am new to PowerShell scripting. For one of my School project I need to generate a report of the entire D Drive. I need to list all the folders sorted according to the size
Summary of the work I have done so far:
I have installed a PowerShell module from this website
https://www.gngrninja.com/script-ninja/2016/5/24/powershell-calculating-folder-sizes
using Install-Module PSFolderSize
After installing if I run the command Get-FolderSize I'm getting the FolderSize for the path I'm running from. The foldersize is not running for all the folders in the directory.
I am facing difficulty traversing through all the folders.
Expected Output:
+-------------+--------------+--------------+-----------+-----------------------+-----------+
| FolderName | Size(Bytes) | Size(MB) | Size(GB) | FullPath | HostName |
+-------------+--------------+--------------+-----------+-----------------------+-----------+
| Disney | 454545448889 | 433488.32024 | 423.32844 | D:\Videos\Disney | localhost |
| Universal | 25454544884 | 24275.34569 | 23.70639 | D:\Videos\Universal | localhost |
| Fox Studios | 8803063287 | 8395.25536 | 8.19849 | D:\Videos\Fox Studios | localhost |
+-------------+--------------+--------------+-----------+-----------------------+-----------+
Can anyone help me where to start?
I would use other tools (like TreeSize) for creating reports like this because of the speed and long filename problematics.
However you could solve your task with the following powershell command without downloading an other Module.
For each subfolder inside your D:\ you have to receive your required data.
You have to calculate the size of each directory by looking for each file Get-ChildItem -Path $Folder.FullName -Recurse -Force and sum up the lenght of all files.
Here you can use the Measure-Object -Property Length -Sum. Depending on the directory size this task will take some time.
Take a look here if you struggle with long file name issues.
After collection and adding all data to an output variable use Select-Object -Property 'FolderName', 'Size(Bytes)', 'Size(MB)', 'Size(GB)', 'FullPath', 'HostName' for sorting the header order.
The command Sort-Object -Property 'Size(Bytes)', 'FolderName' will sort the output depending on the folder size and name.
For a nice looking output use Format-Table.
[System.String]$Path = 'D:\'
[PSCustomObject[]]$Output = #()
foreach ($Folder in (Get-ChildItem -Path $Path -Directory))
{
[System.Int64]$Size = (Get-ChildItem -Path $Folder.FullName -Recurse -Force | Measure-Object -Property Length -Sum).Sum
[System.Collections.Hashtable]$Hashtable = #{
'FolderName' = $Folder.Name
'Size(Bytes)' = $Size
'Size(MB)' = $Size / 1MB
'Size(GB)' = $Size / 1GB
'FullPath' = $Folder.FullName
'HostName' = $env:COMPUTERNAME
}
$Output += New-Object -TypeName 'PSCustomObject' -Property $Hashtable
}
$Output | `
Select-Object -Property 'FolderName', 'Size(Bytes)', 'Size(MB)', 'Size(GB)', 'FullPath', 'HostName' | `
Sort-Object -Property 'Size(Bytes)', 'FolderName' | `
Format-Table
[System.String]$Path = 'D:\'
[PSCustomObject[]]$Output = #()
foreach ($Folder in (Get-ChildItem -Recurse $Path | Where-Object { $_.PSIsContainer }))
{
[System.Int64]$Size = (Get-ChildItem -Path $Folder.FullName -Recurse -Force | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
[System.Collections.Hashtable]$Hashtable = #{
'FolderName' = $Folder.Name
'Size(Bytes)' = $Size
'Size(MB)' = [Math]::Round($Size / 1MB ,2)
'Size(GB)' = [Math]::Round($Size / 1GB,2)
'FullPath' = $Folder.FullName
'HostName' = $env:COMPUTERNAME
}
$Output += New-Object -TypeName 'PSCustomObject' -Property $Hashtable
}
$Output | `
Select-Object -Property 'FolderName', 'Size(Bytes)', 'Size(MB)', 'Size(GB)', 'FullPath', 'HostName' | `
Sort-Object -Property 'Size(Bytes)' , 'FolderName' -Descending | `
Format-Table
Related
I've been searching for a script that simply lists folders in a share and their size. I found the following but I'm getting hung up on how to export the output I'm seeing to an easy to read CSV. It amazes me how something so simple has turned into something difficult. Suggestions welcome!
$colItems = Get-ChildItem "C:\Users\user.name\Desktop" | Where-Object {$_.PSIsContainer -eq $true} | Sort-Object
foreach ($i in $colItems)
{
$subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
$i.FullName + " -- " + "{0:N2}" -f ($subFolderItems.sum / 1MB) + " MB"
}
Based on your script:
## C:\Users\UserName\Desktop\Test\SO_50359947.ps1
$colItems = Get-ChildItem "$($Env:USERPROFILE)\Desktop" |
Where-Object {$_.PSIsContainer} | Sort-Object
$data = ForEach ($i in $colItems){
$subFolderItems = Get-ChildItem $i.FullName -recurse -force -ea 0|
Where-Object {!$_.PSIsContainer} |
Measure-Object -Property Length -sum | Select-Object Sum
[PSCustomObject]#{
Folder = $i.FullName
Size = "{0,10:N2} MB" -f ($subFolderItems.sum / 1MB)
}
}
$data
#$data | Export-Csv "$($Env:USERPROFILE)\Desktop\your.csv" -NoType
Sample output (on a different tree)
> $data
Folder Size
------ ----
Q:\test\2018\03 0,37 MB
Q:\test\2018\04 0,83 MB
Q:\test\2018\05 383,57 MB
Uncomment the last line to write to a csv file.
Here is one way using custom objects:
Get-ChildItem "$home\Desktop" -Directory |
ForEach-Object {
$contents = Get-ChildItem -Path $_.FullName -Recurse
[PsCustomObject]#{
FolderName = $_.Name
SizeMB = [Math]::Round(($contents | Where-Object PsIsContainer -eq $false | Measure-Object -property Length -Sum).Sum / 1MB,2)
SubFolders = ($contents | Where-Object PsIsContainer -eq $true | Measure-Object).Count
Files = ($contents | Where-Object PsIsContainer -eq $false | Measure-Object).Count
}
}
This gives output like this:
FolderName SizeMB SubFolders Files
---------- ------ ---------- -----
Folder1 438.38 19 124
Folder2 34925.72 306 3779
To send this to CSV, simply append the following after the last bracket:
| Export-Csv "$home\Desktop\Folders.csv" -NoTypeInformation
There's a couple ways to do this, but I think the least confusing would be to simply add that information to the item using Add-Member. Then output the desired data via Export-Csv.
$colItems = Get-ChildItem "C:\Users\user.name\Desktop" |
Where-Object {$_.PSIsContainer -eq $true} |
Sort-Object |
%{ Add-Member -InputObject $_ -NotePropertyName 'FolderSize' -NotePropertyValue (Get-ChildItem $_.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object -ExpandProperty Sum) -PassThru}
$colItems | Select FullName,FolderSize | Export-Csv -NoType
Please assign to some variable after getting all the file details from the desktop/any location and create the excel
$subFolderItems = Get-ChildItem "$home\Desktop" -Directory |
ForEach-Object {
$contents = Get-ChildItem -Path $_.FullName -Recurse
[PsCustomObject]#{
FolderName = $_.Name
SizeMB = [Math]::Round(($contents | Where-Object PsIsContainer -eq $false | Measure-Object -property Length -Sum).Sum / 1MB,2)
SubFolders = ($contents | Where-Object PsIsContainer -eq $true | Measure-Object).Count
Files = ($contents | Where-Object PsIsContainer -eq $false | Measure-Object).Count
}
}
$subFolderItems | out-file C:\Users\thiyagu.a.selvaraj\Desktop\PowerShell\FileSizeOutput.xls
In my opinion, using CSV for your use case isn't the best plan because (in my folder) there are files that are over 1000 MB, so csv will break up some file sizes. To make a tab delimited file, which can just as easily be parsed by most systems, simply modify your scripts output string.
I changed the -- to a tab character, and added an output at the end of the line
"{0}`t{1:N2} MB" -f $i.fullname,($subFolderItems.sum / 1MB) >> output.csv
The final script is below; you will probably need to change output.csv to your prefered output file location.
$colItems = Get-ChildItem "C:\Users\user.name\Desktop" | Where-Object {$_.PSIsContainer -eq $true} | Sort-Object
foreach ($i in $colItems)
{
$subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
"{0}`t{1:N2} MB" -f $i.fullname,($subFolderItems.sum / 1MB) >> output.csv
}
If you don't insist on using pure powershell, on Windows 10 (sufficiently new) you can just call bash:
bash -c "du -h | sed 's/\s\+/,/'"
To show how it affects the resulting csv, a longer example:
bash -c "du -m | sed 's/\([0-9]\+\)\s\+\(.*\)/\1MB,\2/'"
I was writing a power shell script to get a size of directory
(get-childitem <path> -recurse | measure-object -property length -sum).sum/1MB
now I want both "size" and "size on the disk" of a folder to be displayed as output
Try this:
GCI <Path> -Recurse |
Group-Object -Property Directory | % {
New-Object psobject -Property #{
Name = $_.Name
Size = ($_.Group | ? {!($_.PSIsContainer)} | Measure-Object Length -Sum).Sum
}
} |
Sort-Object -Property Size -Descending
I have multiple folders across a number of SQL Servers that contain hundreds/thousands of databases. Each database comprises of three elements:
<dbname>.MDF
<dbname>.LDF
<dbname>files (Folder that contains db files/attachments)
I need to marry these files together and add up their total size, does anyone have any advice on how to do this?
EDIT : Just to clarify, I'm currently able to output the filesizes of the MDF/LDF files, I have a separate script that summarises the folder sizes. I need a method of adding together a .MDF/.LDF/DBFiles folder when their name matches. Bearing in mind all of the files are prefixed with the database name.
EDIT #2: The 2 options given so far sum together the .mdf/.ldf files with no problem, but do not add the folder size of the DBFiles folder. Does anyone have any input on how to amend these scripts to include a folder beginning with the same name.
First provided script:
$root = 'C:\db\folder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = Get-ChildItem "$root\$_*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum
}
}
Second provided script:
gci "c:\temp" -file -Include "*.mdf", "*.ldf" -Recurse |
group BaseName, DirectoryName |
%{new-object psobject -Property #{FilesAndPath=$_.Name; Size=($_.Group | gci | Measure-Object Length -Sum).Sum } }
EDIT #3:
Thanks to Ansgar (below), the updated solution has done the trick perfectly. Updating question with final solution:
$root = 'C:\db\folder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = Get-ChildItem "$root\$_*\*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum
}
}
Enumerate just the .mdf files from your database folder, then enumerate the files and folders for each basename.
$root = 'C:\db\folder'
Get-ChildItem "$root\*.mdf" | Select-Object -Expand BaseName |
ForEach-Object {
New-Object -Type PSObject -Property #{
Database = $_
Size = Get-ChildItem "$root\$_*\*" -Recurse |
Measure-Object Length -Sum |
Select-Object -Expand Sum
}
}
if you want the sum of sise files database by dir and name file (without extension), try it
gci "c:\temp" -file -Include "*.mdf", "*.ldf" -Recurse |
group BaseName, DirectoryName |
%{new-object psobject -Property #{FilesAndPath=$_.Name; Size=($_.Group | gci | Measure-Object Length -Sum).Sum } }
Modifiy a little the include gci if necessary
I'm trying to write a PowerShell script retrieving the directory size and owner on my Windows file systems. I've got two separate scripts that work independently, but I don’t know how to put them together as a single script file.
Directory Name and Size:
$startFolder = "C:\Test”
$colItems = (Get-ChildItem $startFolder | Where-Object {$_.PSIsContainer -eq $True} | Sort-Object)
foreach ($i in $colItems)
{
$subFolderItems = (Get-ChildItem $i.FullName | Measure-Object -property length -sum)
$i.FullName + " -- " + "{0:N2}" -f ($subFolderItems.sum / 1MB) + " MB"
}
Directory owner:
Get-ACL C:\Test
I'd like for the script to output to a CSV file.
So something along the lines of this then?
$start = "c:\temp"
$output = "C:\temp\output.csv"
Get-ChildItem $start | Where-Object{$_.PSIsContainer} | ForEach-Object{
$singleFolder = $_.FullName
$folderSize = Get-ChildItem $singleFolder -Recurse -Force | Where-Object{!$_.PSIsContainer} | Measure-Object -Property length -sum | Select-Object -ExpandProperty Sum
$folderSize = [math]::round($folderSize/1MB, 2)
$owner = Get-Acl $singleFolder | Select-Object -ExpandProperty Owner
$_ | Add-Member -MemberType NoteProperty -Name FolderSize -Value $folderSize -PassThru |
Add-Member -MemberType NoteProperty -Name Owner -Value $owner -PassThru
} | Select-Object FullName,FolderSize,Owner | Export-Csv $output -NoTypeInformation
Needed to add some extra logic in length calculation to keep folders out of the mix > Where-Object{!$_.PSIsContainer}. This should work with PowerShell 2.0 just fine.
It loops through each folder in the root of $start and for each $singleFolder calculates the size of the contents and folder owner.
The variables are then added to object through pipeline with Add-Member as the properties FolderSize and Owner. The final Select-Object is used to isolate the properties we want for the output file.
Sample
FullName FolderSize Owner
-------- ---------- -----
C:\temp\37 Place i.Bay domain\guy
C:\temp\adoc42 1103186357 domain\guy
C:\temp\Adoc72 958330505 domain\guy
Notice the empty folder. That output is sent to Export-CSV in the file $output
1)How to create a list of attributes of files with cmdlet get-member and then sort it by last write time?
2)Find total size of files with different extension(for examp total size for all *.html files)
I think the solution for the first task(second task is ok) should be like this(however it doesn't work)
$a=get-childitem . -filter *.html
$n=$a.Length
do{
$isnotsorted=0
for($i=0;$i -lt ($n-1); $i++) {
if ((get-member $a[$i]).LastWriteTime -lt (get-member $a[$i]).LastWRiteTime){
$a[$i],$a[$i+1]=`
$a[$i+1],$a[$i]
$isnotsorted=$i+1
}
}
$n=$isnotsorted
}
until ($n -eq 0)
$a
You don't need to use Get-Member to do this. You can use Sort-Object and Select-Object:
dir C:\ -Force | ? {!$_.PsIsContainer} | Sort LastWriteTime | Select FullName, Attributes
You can use Group-Object and Measure-Object to do this.
((dir D:\Software -Force -Filter *.html | Group Extension).Group | Measure-Object -Sum Length).Sum / 1MB
I'm not sure why you don't want to use Sort-Object -Property LastWriteTime but here is how you would fix your bubble sort code. Remember Get-Member is not the right cmdlet to use to access a properties value.
$a = get-childitem -filter *.html
$n = $a.Length
do {
$isnotsorted = 0
for($i = 0; $i -lt ($n-1); $i++) {
if ( ($a[$i]).LastWriteTime -lt ($a[$i + 1]).LastWRiteTime ) {
$a[$i] , $a[$i+1] = $a[$i+1] , $a[$i]
$isnotsorted = $i + 1
}
}
$n = $isnotsorted
} until ($n -eq 0)
$a
Another thing to note here is that the performance of this algorithm is much worse than just using Sort-Object. My music folder has 1355 files and the above finishes in 83 seconds. Using Sort-Object finishes in 1.7 seconds.
Measure-Command {
get-childitem D:\shares\Music -rec -filter *.m4a | Sort-Object LastWriteTime
}
You don't need Get-Member to display the attributes of files. Just use Get-ChildItem to get the contents of a directory and then pipe them to Sort-Object:
Get-ChildItem -Path $path | Sort-Object -Property 'LastWriteTime'
You can add the -Recurse parameter to Get-ChildItem to list child directories, and add -Force to list files with the Hidden attribute. You can pipe all of this to a Format-* cmdlet if you want to display properties other than those displayed by the standard formatting for files and directories:
Get-ChildItem -Path $path `
| Sort-Object -Property 'LastWriteTime' `
| Format-Table -Property #('Attributes', 'FullName', 'CreationTime')
Get-Member can be used to determine which properties exist on a file or directory object.
You can use Measure-Object with the -Sum switch to add up the Length property of a collection of files:
$htmlFiles = Get-ChildItem -Path $path -Filter '*.html';
$measurement = $htmlFiles | Measure-Object -Property 'Length' -Sum;
$totalHtmlSize = $measurement.Sum;
To generate a table of the total size of each file type you can do something like this:
Get-ChildItem -Path $path `
| Where-Object { $_ -is [IO.FileInfo]; } `
| Group-Object -Property 'Extension' `
| Select-Object `
#{ Name = 'Extension'; Expression = 'Name' }, `
#{ Name = 'TotalSize'; Expression = { `
($_.Group | Measure-Object -Property 'Length' -Sum).Sum } `
} `
| Sort-Object -Property 'Extension';
That retrieves the contents of $path, filters it to only include files, groups the files by the Extension property, projects each group into an object with a property for the extension and a property for the total file size, then sorts the results by extension.