I have following script:
$Extension = "*.jpg"
Get-ChildItem -Path 'C:\Users\DAVID\Documents\Test' -Directory | ForEach-Object {
$FilesInFolder = #($_ | Get-ChildItem -Recurse -Include $Extension -File -Force)
$FileSize = $FilesInFolder | Measure-Object -Property Length -Sum |
Select -ExpandProperty Sum
$FileSize = "{0:N2}" -f ($FileSize/1MB) + " MB"
$NumFiles = $FilesInFolder.Count
}
But it always counts everything in folder includes .zip files and .exe.
What am I doing wrong here? How can I get it to count only .jpg files. Can't find any solution but I'm thinking that it has something with this line to do:
$FilesInFolder = #($_ | Get-ChildItem -Recurse -Include $Extension -File -Force)
I can't fully explain this, because the docs are a little unclear on this issue but your suspicion is right. You have at least two simple ways to get the correct result:
Use -Filter instead of -Include
$FilesInFolder = #($_ | Get-ChildItem -Recurse -Filter $Extension -File -Force)
Explicitly specify the path instead of using the input object
$FilesInFolder = #(Get-ChildItem -Path $_.FullName -Recurse -Include $Extension -File -Force)
Especially the second version makes me think that this is maybe a bug (or at least very strange behaviour) in Get-ChildItem
I think the problem is $_ | Get-ChildItem is not resulting in the Path of the objects being piped to the Path property (because $_ instead has a property named PSPath).
However this seems to work:
$Extension = "*.jpg"
Get-ChildItem -Path 'C:\Users\ab73541\Documents\' -Directory | ForEach-Object {
$FilesInFolder = #(Get-ChildItem $_.PSPath -Recurse -Include $Extension -File -Force)
$FileSize = $FilesInFolder | Measure-Object -property length -Sum | Select -ExpandProperty Sum
$FileSize = "{0:N2}" -f ($FileSize/1MB) + " MB"
$NumFiles = $FilesInFolder.Count }
Related
I would like to get size of user profiles across all servers in OU remotely, I tried this script, but without success
$Exclude = #('admsupp','all users','public','Default','Default user')
$servers = Get-ADComputer -SearchBase "OU=Horizon8,OU=xxx,OU=x,OU=xxx,DC=xx,DC=xx" -Filter *
foreach ($server in $servers)
{
gci -force -path \\$server.dnshostname\c$\users -Exclude $Exclude -ErrorAction SilentlyContinue | ? { $_ -is [io.directoryinfo] } | % {
$len = 0
gci -recurse -force $_.fullname -ErrorAction SilentlyContinue | % { $len += $_.length }
$_.fullname, '{0:N2} GB' -f ($len / 1Gb)
}
}
can someone advise please how to achieve this?
Thank you
The path you construct is wrong.
The way you write \\$server.dnshostname\c$\users will not give you what you think and you should either use a sub expression inside a double-quoted string:
Get-ChildItem -Path "\\$($server.DNSHostName)\c$\users"
or construct it using the -f Format operator like:
Get-ChildItem -Path ('\\{0}\c$\users' -f $server.DNSHostName)
Then, because you don't want to use recursion in the first Get-ChildItem, the -Exclude parameter does not function and instead use the -Directory switch and a Where-Object clause after that to exclude the folders you do not want:
Get-ChildItem -Path "\\$($server.DNSHostName)\c$\users" -Directory | Where-Object { $Exclude -notcontains $_.Name }
As per your comment, if you have server names all starting with a single letter followed by one or more digits and you want to construct a longer path using that, you could do
# construct the path:
# if computername is 'V10testcomputer', this will result in'\\V10testcomputer\c$\Users\testcomputer\AppData'
$path = '\\{0}\c$\users\{1}\AppData' -f $server.DNSHostName, ($server.DNSHostName -replace '^[A-Z]\d+(.*)', '$1')
Get-ChildItem -Path $path -Directory | Where-Object { $Exclude -notcontains $_.Name }
Your problem is the way you construct the Path, see #Theo's answer.
But you can do it far more quickly with Measure-Object instead of another For-Each loop.
You don't have to test the DirectoryInfo type, unless you are still using PowerShell 2, simply use the -Directory parameter.
$Exclude = #('admsupp','all users','public','Default','Default user')
$servers = Get-ADComputer -SearchBase "OU=Horizon8,OU=xxx,OU=x,OU=xxx,DC=xx,DC=xx" `
-Filter *
foreach ($server in $servers)
{
gci -Force -Path "\\$($server.dnshostname)\c$\users" -Exclude $Exclude `
-Directory -ErrorAction SilentlyContinue |
% {
$_.Fullname, '{0:N2} GB' -f ((gci -Recurse -Force $_.Fullname `
-ErrorAction SilentlyContinue | Measure-Object `
-Property Length -Sum).Sum / 1Gb)
}
}
I Suggest you to prefer this
$_.Fullname, (gci -Recurse -Force $_.Fullname -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum).Sum
because reusing this info is easier than text data
#theo
Hi,
currently I am running this script
$Exclude = #('admsupp','all users','public','Default','Default user')
$servers = Get-ADComputer -SearchBase "OU=xxx,OU=xxx,OU=xxx,DC=xxx,DC=xxx" -Filter *
$path = '\\{0}\c$\users\{1}\AppData\roaming' -f $server.name, ($server.name -replace '^[A-Z]\d+(.*)', '$1')
foreach ($server in $servers) {
$colItems = Get-ChildItem -Path $path -Exclude $Exclude | 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 / 1GB) + ” GB” >> C:\users\xxx\export.txt
$i.FullName + ”;” + “{0:N2}” -f ($subFolderItems.sum / 1GB) + ” GB”
}
}
excludes are working fine like this, but the script failes immediately after start without any error message. Only thing that I have changed is the path regarding your advice:$path = '\\{0}\c$\users\{1}\AppData\roaming' -f $server.name, ($server.name -replace '^[A-Z]\d+(.*)', '$1')
I have found several resources that use the following script to get folder sizes
$colItems = (Get-ChildItem $startFolder -recurse | 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"
}
The problem with that is it also lists the subdirectories ie:
c:\test\1 -- 10mb
c:\test\1\folder -- 10mb
c:\test\1\folder\deep -- 5mb
c:\test\1\folder\tuna -- 5mb
c:\test\2 -- 20bm
c:\test\2\folder -- 20mb
c:\test\2\folder\deep -- 10mb
c:\test\2\folder\tuna -- 10mb
I think you know see where I am going. What I am looking for is just the parent folder's results... SO:
c:\test\1 -- 10mb
c:\test\2 -- 20mb
How can this be accomplished with Powershell?
....
You need to get the total contents size of each directory recursively to output. Also, you need to specify that the contents you're grabbing to measure are not directories, or you risk errors (as directories do not have a Length parameter).
Here's your script modified for the output you're looking for:
$colItems = Get-ChildItem $startFolder | 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"
}
This simple solution worked for me as well.
Get-ChildItem -Recurse 'directory_path' | Measure-Object -Property Length -Sum
The solution posted by #Linga:
"Get-ChildItem -Recurse 'directory_path' | Measure-Object -Property Length -Sum" is nice and short. However, it only computes the size of 'directory_path', without sub-directories.
Here is a simple solution for listing all sub-directory sizes. With a little pretty-printing added.
(Note: use the -File option to avoid errors for empty sub-directories)
foreach ($d in gci -Directory -Force) {
'{0,15:N0}' -f ((gci $d -File -Recurse -Force | measure length -sum).sum) + "`t`t$d"
}
Sorry to reanimate a dead thread, but I have just been dealing with this myself, and after finding all sorts of crazy bloated solutions, I managed to come up with this.
[Long]$actualSize = 0
foreach ($item in (Get-ChildItem $path -recurse | Where {-not $_.PSIsContainer} | ForEach-Object {$_.FullName})) {
$actualSize += (Get-Item $item).length
}
Quickly and in few lines of code gives me a folder size in Bytes, than can easily be converted to any units you want with / 1MB or the like.
Am I missing something? Compared to this overwrought mess it seems rather simple and to the point. Not to mention that code doesn't even work since the called function is not the same name as the defined function. And has been wrong for 6 years. ;)
So, any reasons NOT to use this stripped down approach?
This is similar to https://stackoverflow.com/users/3396598/kohlbrr answer, but I was trying to get the total size of a single folder and found that the script doesn't count the files in the Root of the folder you are searching. This worked for me.
$startFolder = "C:\Users";
$totalSize = 0;
$colItems = Get-ChildItem $startFolder
foreach ($i in $colItems)
{
$subFolderItems = Get-ChildItem $i.FullName -recurse -force | Where-Object {$_.PSIsContainer -eq $false} | Measure-Object -property Length -sum | Select-Object Sum
$totalSize = $totalSize + $subFolderItems.sum / 1MB
}
$startFolder + " | " + "{0:N2}" -f ($totalSize) + " MB"
This is something I wind up looking for repeatedly, even though I wrote myself a nice little function a while ago. So, I figured others might benefit from having it and maybe I'll even find it here, myself. hahaha
It's pretty simple to paste into your script and use. Just pass it a folder object.
I think it requires PowerShell 3 just because of the -directory flag on the Get-ChildItem command, but I'm sure it can be easily adapted, if need be.
function Get-TreeSize ($folder = $null)
{
#Function to get recursive folder size
$result = #()
$folderResult = "" | Select-Object FolderPath, FolderName, SizeKB, SizeMB, SizeGB, OverThreshold
$contents = Get-ChildItem $folder.FullName -recurse -force -erroraction SilentlyContinue -Include * | Where-Object {$_.psiscontainer -eq $false} | Measure-Object -Property length -sum | Select-Object sum
$sizeKB = [math]::Round($contents.sum / 1000,3) #.ToString("#.##")
$sizeMB = [math]::Round($contents.sum / 1000000,3) #.ToString("#.##")
$sizeGB = [math]::Round($contents.sum / 1000000000,3) #.ToString("#.###")
$folderResult.FolderPath = $folder.FullName
$folderResult.FolderName = $folder.BaseName
$folderResult.SizeKB = $sizeKB
$folderresult.SizeMB = $sizeMB
$folderresult.SizeGB = $sizeGB
$result += $folderResult
return $result
}
#Use the function like this for a single directory
$topDir = get-item "C:\test"
Get-TreeSize ($topDir)
#Use the function like this for all top level folders within a direcotry
#$topDir = gci -directory "\\server\share\folder"
$topDir = Get-ChildItem -directory "C:\test"
foreach ($folderPath in $topDir) {Get-TreeSize $folderPath}
My proposal:
$dir="C:\temp\"
get-childitem $dir -file -Rec | group Directory | where Name -eq $dir | select Name, #{N='Size';E={(($_.Group.Length | measure -Sum).Sum / 1MB)}}
from sysinternals.com with du.exe or du64.exe -l 1 .
or 2 levels down:
**du -l 2 c:**
Much shorter than Linux though ;)
At the answer from #squicc if you amend this line: $topDir = Get-ChildItem -directory "C:\test" with -force then you will be able to see the hidden directories also. Without this, the size will be different when you run the solution from inside or outside the folder.
I used the great answer of #kohlbrr and improved it a bit. I also turned it into a function you can put in your $PROFILE. This outputs three properties instead of just text: Name, Size (which is a string output of the size converted to MB), and Value which is the raw size value you can use with | sort value
function Get-DirectorySize([string] $rootFolder) {
$colItems = Get-ChildItem $rootFolder | 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
[PSCustomObject]#{ Name=$i.Fullname; Size="{0:N2}" -f ($subFolderItems.sum / 1MB) + " MB"; Value=$subFolderItems.sum }
}
}
The following script provides file sizes from a directory(not going deep) and sizes in bytes.(give your path in $($args[0]) in both the scripts)
Get-ChildItem -Path "$($args[0])" -Recurse -Depth 0 -file| select Length,LastWriteTime,FullName | Export-Csv .\FileAndFolderSizes.csv -NoTypeInformation
The following script provides the folder sizes(depth 0 ) in bytes within the given directory.
$array= #()
Get-ChildItem -Path "$($args[0])" -Recurse -Depth 0 | Where-Object { $_.PSIsContainer } |
ForEach-Object {
$obj = New-Object PSObject
$Size = [Math]::Round((Get-ChildItem -Recurse $_.FullName | Measure-Object Length -Sum -ErrorAction SilentlyContinue).Sum, 2)
$obj |Add-Member -MemberType NoteProperty -Name "FullName" $_.FullName
$obj |Add-Member -MemberType NoteProperty -Name "LastWriteTime" $_.LastWriteTime
$obj |Add-Member -MemberType NoteProperty -Name "Length" $Size
$array +=$obj
}
$array | select Length,LastWriteTime,FullName | Export-Csv .\FileAndFolderSizes.csv -NoTypeInformation -Append
Output is as follows
"Length","LastWriteTime","FullName"
"593408","2/17/2022 10:51:01 PM","C:\a_appli\Partners_Ref\Client64_Rws2\compresslayer.dll"
"286720","2/9/2021 11:52:18 PM","C:\a_appli\Partners_Ref\Client64_Rws2\fdsrtd.dll"
"589312","6/19/2019 10:18:41 PM","C:\a_appli\Partners_Ref\Client64_Rws2\FdswCli.dll"
"13658276","3/18/2022 9:52:16 AM","C:\a_appli\Partners_Ref\Client64_Rws2\PartnersTemplateBuilder"
Interesting how powerful yet how helpless PS can be in the same time, coming from a Nix learning PS. after install crgwin/gitbash, you can do any combination in one commands:
size of current folder:
du -sk .
size of all files and folders under current directory
du -sk *
size of all subfolders (including current folders)
find ./ -type d -exec du -sk {} \;
I want to copy a file to multiple destinations using a script that filters through a directory and selects the newest file in the $File_path then change its name and copies it to the $destination, the script i'm using is this:
$File_path = "C:\TEMP\export\liste\Text_Utf8\"
$destination = "C:\TEMP\export\C7E001"
get-childitem -path $File_path -Filter "Ges?*.txt" |
where-object { -not $_.PSIsContainer } |
sort-object -Property $_.CreationTime |
select-object -last 1 | copy-item -Destination (join-path $destination "FRER3000CCFETES01_IN.DEV")
this only copies it to one location, is there a way to improve it to copy the same file to multiple locations? i have seen this thread but it seems different.
the other locations are as follow:
C:\TEMP\export\C7P001
C:\TEMP\export\C7F001
C:\TEMP\export\C7S001
and so on.
thank you.
Although my answer isn't very different to Peter's answer, This uses the LastWriteTime property to get the latest file and uses the FullName property of the file to copy in the Copy-Item cmdlet.
$File_path = "C:\TEMP\export\liste\Text_Utf8"
$destinations = "C:\TEMP\export\C7E001", "C:\TEMP\export\C7F001", "C:\TEMP\export\C7S001"
$fileToCopy = Get-ChildItem -Path $File_path -Filter "Ges*.txt" -File |
Sort-Object -Property $_.LastWriteTime |
Select-Object -Last 1
foreach ($dest in $destinations) {
Copy-Item -Path $fileToCopy.FullName -Destination (Join-Path -Path $dest -ChildPath "FRER3000CCFETES01_IN.DEV")
}
You can use an foreach object loop
$File_path = "C:\TEMP\export\liste\Text_Utf8\"
$destination = "C:\TEMP\export\C7E001", "C:\TEMP\export\C7P001", "C:\TEMP\export\C7F001", "C:\TEMP\export\C7S001"
$Files = get-childitem -path $File_path -Filter "Ges?*.txt" |
where-object { -not $_.PSIsContainer } |
sort-object -Property $_.CreationTime |
select-object -last 1
$Destination | Foreach-Object {copy-item $Files -Destination (join-path $_ "FRER3000CCFETES01_IN.DEV")}
Currently , I can export the list to a text file and separate them by share name.
My question is : I want to be able to count the number of files in the directory as well as the number of folders into a separate text file.
I'd like to do in this format for text file , $hostname-$sharename-count.txt
For example:
My desired output:
1000 #Folder count
150 #File count
Here is what I have so far:
$outputDir = 'C:\Output'
$Shares = Get-WmiObject Win32_Share -Filter "not name like '%$'"
$re = ($Shares | ForEach-Object {[Regex]::Escape($_.Path)}) -join '|'
foreach ($Share in $Shares) {
$result = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName) -replace "^($re)\\"
# output the results per share in a text file
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}.txt' -f $env:COMPUTERNAME, $Share.Name)
$result | Out-File -FilePath $fileOut -Force
}
You can simply expand the code you have like below:
$outputDir = 'C:\Output'
$Shares = Get-WmiObject Win32_Share -Filter "not name like '%$'"
$re = ($Shares | ForEach-Object {[Regex]::Escape($_.Path)}) -join '|'
foreach ($Share in $Shares) {
$files = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName) -replace "^($re)\\"
# output the list of files per share in a text file
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}.txt' -f $env:COMPUTERNAME, $Share.Name)
$files | Out-File -FilePath $fileOut -Force
# output the count results for files and folders per share in a text file
$folders = Get-ChildItem -Path $Share.Path -Directory -Recurse
$content = 'Folders: {0}{1}Files: {2}' -f $folders.Count, [Environment]::NewLine, $files.Count
$fileOut = Join-Path -Path $outputDir -ChildPath ('{0}-{1}-count.txt' -f $env:COMPUTERNAME, $Share.Name)
$content | Out-File -FilePath $fileOut -Force
}
P.S. You can add switch -Force to the Get-ChildItem cmdlet to also get the hidden or system files listed if there are any such files inside the shares
If you just want to have a count, you could do something like this:
$resultForFiles = (Get-ChildItem -Path $Share.Path -File -Recurse | Select-Object -Expand FullName)
$resultForFolders = (Get-ChildItem -Path $Share.Path -Directory -Recurse | Select-Object -Expand FullName)
$resultForFiles.Count | Out-File "Path" -Append
$resultForFolders.Count | Out-File "Path" -Append
The -File switch for Get-ChildItem will only get files and the -Directory will only get folders
You can do this in just one line of code
Get-ChildItem | Measure-Object -Property Mode
The property Mode from Get-ChildItem tells you if you are getting folders, files or others.
You can also use get-help Measure-Object -Examples to check some useful examples on measuring files and folders
I am trying to find all files in a specific drive that are accessed before 40 days, find their file type and specificy size of files based on extension.
I have 40000 files in 126 folders, and total of 51 different extensions (file types), now that i want to find what type of file occupy who much space.
With this I got file count based on extension:
Get-ChildItem -Path X:\ -Recurse |where{-not $_.PSIsContainer} | group Extension -NoElement
With this I got number of unique extensions:
Get-ChildItem -Path X:\ -Recurse | Select-Object -Property Extension -Unique
Get-ChildItem -Path X:\ -Recurse |where{-not $_.PSIsContainer} | group Extension -NoElement
Get-ChildItem -Path X:\ -Recurse | Select-Object -Property Extension -Unique
Maybe try this.
# directory path
$directory = "C:\Program Files"
# date -40 days
$date = (Get-Date).AddDays(-40)
# files which are accessed before 40 days
$files = Get-ChildItem $directory -Recurse -File:$true | Where-Object {$_.LastWriteTime -gt $date}
# sort files by extension, size
$files | Sort-Object Extension,Length | Select-Object Name,#{label = 'Length'; e = {"{0:N3} KB" -f ($_.Length / 1KB)}} | ft -AutoSize -Wrap
I'll hope it is not so bad. :)
# directory path
$directory = "X:\"
# date -40 days
$date = (Get-Date).AddDays(-40)
# files which are accessed before 40 days
$files = Get-ChildItem $directory -Recurse -File:$true | Where-Object {$_.LastWriteTime -gt $date}
# file extensions
$fileExtensions = $files | Select-Object -Property Extension -Unique
foreach ($ext in $fileExtensions){
[int]$fileSize = $null
foreach ($file in $files) {
if ($file.Extension -like $ext.Extension) {
[int]$fileSize += $file.Length / 1KB
}
}
Write-Host "Extension:" $ext.Extension " - Size: "$fileSize "KB"
}
Maybe something like this, I'm not sure how to format it in a table:
$files = Get-ChildItem $directory -Recurse -File:$true | Where-Object {$_.LastWriteTime -gt $date}
foreach($file in $files){
[IO.Path]::GetExtension($file)
$file.length
}