I have about 1600 old home drives that I need to capture the folder sizes on. They are spread across 12 NAS Appliances and I need to get the size of each folder. I see this asked a lot but they are always asking for all the shares on a single server.
I have used simple one-liners like the the one below which work great.
Get-ChildItem \\Server1\Users\User1 -file -recurse | Measure-Object -Sum Length
How can I feed in a txt or csv from multiple locations?
Like
\\Server1\Users\User1
\\Server2\Users\User1
\\Server3\Users\User1
\\Server4\Users\User1
\\Server5\Users\User1
\\Server6\Users\User1
\\Server7\Users\User1
etc...
Exporting to a csv would be nice as well.
thanks!!
You can use Get-Content to read your text file line-by-line:
Get-Content .\path\to\file.txt
Next up we need to repeat your one-liner for each line:
Get-Content .\path\to\file.txt |ForEach-Object {
Get-ChildItem $_ -File -Recurse | Measure-Object -Sum Length
}
This will give us 1600 individual measurements - but now we won't know which paths they belong to...
To track which measurement belongs to which user directory, let's create a new object containing both all the information instead:
Get-Content .\path\to\file.txt |ForEach-Object {
$Measurement = Get-ChildItem $_ -File -Recurse | Measure-Object -Sum Length
[pscustomobject]#{
Path = $_
FileCount = $Measurement.Count
TotalSize = $Measurement.Sum
}
}
Finally, we can export to CSV using Export-Csv:
Get-Content .\path\to\file.txt |ForEach-Object {
$Measurement = Get-ChildItem $_ -File -Recurse | Measure-Object -Sum Length
[pscustomobject]#{
Path = $_
FileCount = $Measurement.Count
TotalSize = $Measurement.Sum
}
} |Export-Csv .\path\to\output.csv -NoTypeInformation
Related
I have an applications folder that have more than 10 applications in. I want to list all files (including sub-folders) with directory and size info and save it under each application folder.
Here is the script (it is in C:\Users\xxxxxx\Desktop\apps)
$FolderList = Get-ChildItem -Directory
foreach ($folder in $FolderList)
{
$thisPath = Get-Location
Get-ChildItem -File -Filter * -Path $folder -Recurse |
Sort-Object -Property Length -Descending|
Select-Object -Property FullName, Length, #{l='Length (MB)';e={$_.Length/1MB}} |
Format-Table -AutoSize |
Out-File $thisPath\fileList_$folder.txt
}
Output:
FullName - Length - Length (MB)
C:\Users\xxxxxx\Desktop\apps\3\VSCodeUserSetup-x64-1.62.2.exe 79944464 76.2409820556641
C:\Users\xxxxxx\Desktop\apps\3\son.zip 18745870 17.8774547576904
It does what I want but in some of the outputs where the path is too long it didn't write the length or even full path.
FullName
C:\Users\xxxxxx\Desktop\apps\3\xxxxxxxxxxx/xxxxxx/xxxxxxxxxxxxxx/xxxxxxxxxxx/VSCodeUserSetu...
C:\Users\xxxxxx\Desktop\apps\3\son.zip
As I searched I saw that there is a char limit. How can I overcome this issue?
The -Path parameter is defined as a string array, but you are feeding it a DirectoryInfo object.
The second part of your question is about truncation, which happens because you use Format-Table -AutoSize on the data.
Format-* cmdlets are designed to display output on the console window only which has a limited width and all items longer are truncated.
Rule of Thumb: never use Format-* cmdlets when you need to process the data later.
Instead of saving a formatted table to a text file, I would suggest saving the (object) info as structured CSV file which makes working with the data later MUCH easier and without truncation. (you can for instance open it in Excel)
# just get an array of Full pathnames
$FolderList = (Get-ChildItem -Directory).Name #instead of Fullname
foreach ($folder in $FolderList) {
# create the path for the output
$fileOut = Join-Path -Path $folder -ChildPath ('filelist_{0}.csv' -f $folder)
Get-ChildItem -File -Path $folder -Recurse |
Sort-Object -Property Length -Descending |
Select-Object -Property FullName, Length, #{l='Length (MB)';e={$_.Length/1MB}} |
Export-Csv -Path $fileOut -NoTypeInformation -UseCulture
}
I added switch -UseCulture to the Export-Csv cmdlet so you can afterwards simply double-click the csv file to open it in your Excel
I am trying to get complete a request of amount of files in a directory and then the total size of that directory. I've come up with this:
Get-Content -Path C:\Users\$USERNAME%\Documents\list.txt |
Foreach-Object {
cd $_
Write-Host $_
(Get-ChildItem -Recurse -File | Measure-Object).Count
(ls -r|measure -sum Length).Sum
}
The txt file has contents such as:
\\directory\on\network\1
\\directory\on\network\also
Ultimately I need this in a spreadsheet, but I am failing with formatting. As is, it outputs straight to powershell, so with thousands of directories this isn't ideal. I've tried exporting to CSV but it overwrites the CSV with each result, and when I tried setting the function equal to a variable array and then exporting that, it simply output a blank file.
Any assistance with this is appreciated.
In order to export to CSV you will need an object with properties. Your code generates a few values without any structure. Surely the % in your sample code is a typo, it definitely doesn't belong there. It is generally considered bad practice to use aliases in scripts, however you should, at a minimum, keep it consistent. One line you use Get-ChildItem/Measure-Object and the next use ls/measure. Regardless you don't show your export, so it's hard to help with what we can't see. You also don't need to CD into the directory, it seems it would only slow the script down if anything.
The easiest way I know to create an object is to use the [PSCustomObject] type accelerator.
$infile = "C:\Users\$USERNAME\Documents\list.txt"
$outfile = "C:\some\path\to.csv"
Get-Content -Path $infile |
Foreach-Object {
Write-Host Processing $_
[PSCustomObject]#{
Path = $_
Total = (Get-ChildItem $_ -Recurse -File | Measure-Object).Count
Size = (Get-ChildItem $_ -Recurse -File | Measure-Object -sum Length).Sum
}
} | Export-Csv $outfile -NoTypeInformation
Edit
We should've ran the Get-Childitem call once and then pulled the info out. The first option is in "pipeline" mode can save on memory usage but might be slower. The second puts it all in memory first so it can be much quicker if it's not too large.
Get-Content -Path $infile |
Foreach-Object {
Write-Host Processing $_
$files = Get-ChildItem $_ -Recurse -File | Measure-Object -sum Length
[PSCustomObject]#{
Path = $_
Total = $files.Count
Size = $files.Sum
}
} | Export-Csv $outfile -NoTypeInformation
or
$results = foreach($folder in Get-Content -Path $infile)
{
Write-Host Processing $folder
$files = Get-ChildItem $folder -Recurse -File | Measure-Object -sum Length
[PSCustomObject]#{
Path = $folder
Total = $files.Count
Size = $files.Sum
}
}
$results | Export-Csv $outfile -NoTypeInformation
The -append flag in Export-Csv allows you to add to an existing file rather than overwriting.
I am trying to get the number of files inside folders and number of folders along with total size. To a certain extent I have achieved that goal but when I am trying it for checking millions of folders/files and their size may be around 1 TB its getting stuck might be getting into infinite lope.
Also I want to compare the two location size and number of files/folder and get output as bollen value. – true if the size and numbers match, false if they don’t.
Below script is what I tried. Can some one help me with the requirement.
$hostnames = Get-Content C:\server.txt
$directory = "D$\logs"
foreach ($hostname in $hostnames){
$Folderitems = (Get-ChildItem -Path "\\$hostname\$directory" -Directory -Recurse -Force).Count
$FileItems = Get-ChildItem -path "\\$hostname\$directory" -recurse
$Measurement = $FileItems | Measure-Object -property length -sum
$colitems = $FileItems | measure-Object -property length -sum
"$hostname,$directory;{0:N2}" -f ($colitems.sum / 1024MB) + "GB;" + $Measurement.count + " files;" + $items +"Folders;"
}
A performance improvement would be to invoke the Get-ChildItem cmdlet only once and use it to filter the Folders using the Where-Object cmdlet:
$FileItems = Get-ChildItem -path "\\$hostname\$directory" -recurse
$Folderitems = $FileItems | Where-Object PsIsContainer
You also calculate the length twice, remove one of these:
$Measurement = $FileItems | Measure-Object -property length -sum
$colitems = $FileItems | measure-Object -property length -sum
Also i want to compare the two location size and number of
files/folder and get output as bollen value.
Which two locations you want to compare? You are iterating over a list of hostnames and don't store any values...
Edit to your comment:
Regarding the comparison part i want to compare the size and number of
files from server1 to server2 for location d$\website. Its just like
same we do right click on folder and see the files and size.
Currently, you are retrieving the items for D$\logs, not D$\website you probably have to change this?!. To compare the results, you have to store them first. I would recommend an array of PSCustomObjects. The structure looks like this (sample output):
Server Sum Count
------ --- -----
YourServer1 88575206 386
YourServer2 88575206 386
And here the script:
foreach ($hostname in $hostnames){
$FileItems = Get-ChildItem -path "\\$hostname\$directory" -recurse
$Folderitems = $FileItems | Where-Object PsIsContainer
$Measurement = $FileItems | Measure-Object -property length -sum
$serverFileMeasurements += [PSCustomObject]#{
Server = $hostname
Sum = $Measurement.Sum
Count = $Measurement.Count
}
}
# assuming there are only two servers:
if ($serverFileMeasurements[0].Count -eq $serverFileMeasurements[1].Count -and
$serverFileMeasurements[0].Sum -eq $serverFileMeasurements[1].Sum)
{
Write-Host $true
}
else
{
Write-Host $false
}
I have code that finds if a file/folder exists or not in a different location, basically compares two folders. I cannot seem to find anything online to also search file size differences. My code is below and I just need help on how to recursively search and find file size differences as well.
$source = Get-ChildItem -Recurse -path "C:\Users\Cl\Desktop\Source"
$compare = Get-ChildItem -Recurse -path "C:\Users\Cl\Desktop\WMIS"
Compare-Object -ReferenceObject $source -DifferenceObject $compare -PassThru
Use measure-object to compare file sizes, then if you want to do something afterwards (like copy the updated one to the destination) store them in a variable and create if statements accordingly. You can use get-member to view the properties you can use. I think this gives you the sizes in bytes so divide the results by "1GB". Try something like this:
$source = gci "c:\users\c1\desktop\source" -recurse | Measure-Object -property length -sum
#$source = ($source.sum / 1GB)
$compare = gci "c:\users\c1\desktop\WMIS" -recurse | Measure-Object -property length -sum
#$compare= ($compare.sum / 1GB)
Here is what I am trying to do:
Search my computer for files ending with a .doc, .docx, .xls, or .xlsx
Output the filenames and sizes (in groups by file extension) to a text file named “File_Summary.txt”.
I also want the total of the number of files and total file size for each file extension listed in the output.
I can't even get past the check folder part:
$Folder_To_Check = C:\AIU
$Report_File_Location = "File_Summary.txt"
$files= Get-Childitem -Path $Folder_To_Check-Include *doc, *docx, *xls, *xlsx $Report_File_Location
$totalfiles = ($files | Measure-Object).Count
$totalsize = ($files | Measure-Object -Sum Length).Sum
Update. Here is my code again with some changes I made from the suggestions, but I'm still coming up empty.
$Report_File_Location = "File_Summary.txt"
$files= Get-Childitem C:\AIU -include "*doc", "*docx", "*xls", "*xlsx"-recurse | Sort-Object | Get-Unique -asString
$files | Out-File $Report_File_Location
$totalfiles = ($files | Measure-Object).Count
$totalsize = ($files | Measure-Object -Sum Length).Sum
write-host "totalfiles: $totalfiles"
write-host "totalsize: $totalsize"
The more I was looking about this I think I shouldn't use the Sort-Object but to use Group Extension -NoElement | Sort Count -Descending that would give me the total number of files for each type?
UPDATE
Thanks to help of people here I got my code to work. But I had an issue where it was saying that my file didn't exist. The problem? I needed to list the entire folder path and use SINGLE quotes.
This code works:
$Folder_To_Check = 'C:\Users\Sarah\Documents\AIU'
$Report_File_Location = "File_Summary.txt"
$results = Get-ChildItem $Folder_To_Check -Include *.doc,*.docx,*.xls,*.xlsx -Recurse
$results | Group-Object extension | ForEach-Object {
[PSCustomObject]#{
Results = $_.Name
Count = $_.Count
Size = [Math]::Round(($_.Group | Measure-Object -Sum Length | Select-Object - ExpandProperty Sum) / 1MB,2)
}
} | Out-File $Report_File_Location -Append
BIG props to Matt for helping me organize my results so nice. Thank you for helping me learn.
$Folder_To_Check = C:\AIU
$Report_File_Location = "File_Summary.txt"
$results = Get-ChildItem $Folder_To_Check -Include *.doc,*.docx,*.xls,*.xlsx -Recurse
$results | Group-Object extension | ForEach-Object {
[PSCustomObject]#{
Extension = $_.Name
Count = $_.Count
Size = [Math]::Round(($_.Group | Measure-Object -Sum Length | Select-Object -ExpandProperty Sum) / 1MB,2)
}
} | Out-File $Report_File_Location -Append
Get all of the files you are looking for with Get-ChildItem much like you were. Vasja mentioned it as well that you might want to use -Recurse to get results from sub directories as well. Use Group-Object to collect the files by extension. For each collection output a custom object of the extension and file count, which both come Group-Object, and the size of all the files of that particular extension converted to MB and rounded to 2 decimal places.
Update for 2.0
In case you only have 2.0 installed I wanted to provide and answer that works for that.
$results | Group-Object extension | ForEach-Object {
$properties = #{
Extension = $_.Name
Count = $_.Count
Size = [Math]::Round(($_.Group | Measure-Object -Sum Length | Select-Object -ExpandProperty Sum) / 1MB,2)
}
New-Object -TypeName PSObject -Property $properties
}
Added some quotes.
Also you probably want -Recurse on Get-Childitem
$Folder_To_Check = "C:\AIU"
$Report_File_Location = "E:\tmp\File_Summary.txt"
$files = Get-Childitem -Path $Folder_To_Check -Include *doc, *docx, *xls, *xlsx -Recurse
$files | Out-File $Report_File_Location
$totalfiles = ($files | Measure-Object).Count
$totalsize = ($files | Measure-Object -Sum Length).Sum
write-host "totalfiles: $totalfiles"
write-host "totalsize: $totalsize"
Yep, you need a collection of strings for the -Include argument. So, what you tried is one string, that being:
"*doc, *docx, *xls, *xlsx"
While the commas do need to seperate the extensions when you include it within the quotes it thinks that's a part of the one thing to include, so it's seriously looking for files that have anything (as per the asterisk) then "doc," then anything then "docx," then anything then... you see where I'm going. It thinks it has to include all of that. Instead you need a collection of strings like:
-Include "*doc","*docx","*xls","xlsx"
I hope that helps. Here's your line modified to what should work:
$files= Get-Childitem -Path $Folder_To_Check-Include "*doc", "*docx", "*xls", "*xlsx"