I would like to be able to select a remote folder and scan it recursively for all file extensions. For each extension discovered, I would need a total count and well as the sum for individual file types.
I've found a script here that works for a single file extension using the -include switch, but rather than running the script scores of times, it would be nice to simply run once and collect all extensions.
$hostname=hostname
$directory = "D:\foo"
$FolderItems = Get-ChildItem $directory -recurse -Include *.txt
$Measurement = $FolderItems | Measure-Object -property length -sum
$colitems = $FolderItems | measure-Object -property length -sum
"$hostname;{0:N2}" -f ($colitems.sum / 1MB) + "MB;" + $Measurement.count + " files;"
I think I need to use Get-ChildItem $directory | Group-Object -Property Extension to somehow list the extensions, if that's helpful.
The ideal output would be something like this:
Extension, Size (MB), Count
jpg,1.72,203
txt,0.23,105
xlsx,156.12,456
I'm using Powershell v4.0 on a Windows 7 machine to remotely connect to the server, I could run the script locally, but it only has V3.0 for the Win 2008 R2 machine.
Does anyone have any ideas?
This is one approach:
#Get all items
Get-ChildItem -Path $directory -Recurse |
#Get only files
Where-Object { !$_.PSIsContainer } |
#Group by extension
Group-Object Extension |
#Get data
Select-Object #{n="Extension";e={$_.Name -replace '^\.'}}, #{n="Size (MB)";e={[math]::Round((($_.Group | Measure-Object Length -Sum).Sum / 1MB), 2)}}, Count
Extension Size (MB) Count
--------- --------- -----
mkv 164,03 1
xlsx 0,03 3
dll 0,32 5
lnk 0 1
url 0 1
txt 0 1
Related
#Get-ChildItem get the items from the path where the script is run
# only those files are fetched which has the extension .jpg
Get-ChildItem -Path *.jpg |
#using Where-Object and using the length property of the file
#to fetch only those files which are greater 10000 in size
Where-Object {$_.length -gt 10000} |
#sorting the files by length using Sort-Object
Sort-Object -Property length |
#formatting the out to only name and length of files
Format-Table -Property name, length |
#writing the file using Out-File to a text file Output.txt
Out-File -FilePath .\Output.txt
i already did. But i need another script as mentioned in heading.
If I understood correctly, you want collect files from several folders, and then generate your report. There are multiple ways to do it
Example 1 (Get-ChildItem can take a list of folders)
$MyFolders = 'C:\Temp\','D:\Docs\','\\server01\fileShare2\'
#Get-ChildItem get the items from the several fodlers
# only those files are fetched which has the extension .jpg
Get-ChildItem -Path $MyFolders -Filter *.jpg |
#using Where-Object and using the length property of the file
#to fetch only those files which are greater 10000 in size
Where-Object {$_.length -gt 10000} |
#sorting the files by length using Sort-Object
Sort-Object -Property length |
#formatting the out to only name and length of files
Format-Table -Property name, length |
#writing the file using Out-File to a text file Output.txt
Out-File -FilePath .\Output.txt
Example 2 (run several Get-ChildItem commands, combine results in an single array, and then generate report)
$MyFolders = 'C:\Temp\','D:\Docs\','\\server01\fileShare2\'
#Get-ChildItem get the items from the several fodlers
# only those files are fetched which has the extension .jpg
(Get-ChildItem -Path 'C:\Temp\' -Filter *.jpg) + (Get-ChildItem -Path 'D:\Docs\' -Filter *.jpg) |
#using Where-Object and using the length property of the file
#to fetch only those files which are greater 10000 in size
Where-Object {$_.length -gt 10000} |
#sorting the files by length using Sort-Object
Sort-Object -Property length |
#formatting the out to only name and length of files
Format-Table -Property name, length |
#writing the file using Out-File to a text file Output.txt
Out-File -FilePath .\Output.txt
There are more ways to archive the same results, such as using expressions $(...), arrays #(...), scriptblocks &{...}
I have a task to carry out 3 times a day on a WS2012R2 to get the Disk size, total number of files and folders including subdirectories from a folder on a remote server.
Currently I get this information by RDP'ing to the target, navigating to the folder and right clicking the folder to copy the info:
I have already tried the PowerShell script :
Get-ChildItem E:\Data -Recurse -File | Measure-Object | %{$_.Count}
and other PowerShell scripts.
Which produced countless errors pertaining to not having permissions for some sub directories or simply gave results I didn't want such.
I have tried VBscript but VBscript simply cannot get this information.
You can just access the count property:
$items = Get-ChildItem E:\Data -Recurse -File
($items | Where { -not $_.PSIsContainer}).Count #files
($items | Where $_.PSIsContainer).Count #folders
To summarise the comments so far.
You can get the size of the C drive with:
$Drive = "C"
Get-PSDrive -Name $Drive | Select-Object #{N="Used Space on $Drive Drive (GB)"; E={[Math]::Round($_.Used/1GB)}}
But you cannot use something like the code below to count the files & folders for the whole C drive, but it works for simple filestructures and simple drives.
I use the code to calculate my other drives and for my homepath, just change $Path to e.g "$Env:Homepath".
There's the path length problem which is a .NET thing and won't be
fixed until everyone (and PowerShell) is using .NET 4.6.2. Then
there's that you're acting as you counting it, not the operating
system counting.
[Int]$NumFolders = 0
[Int]$NumFiles = 0
$Path = "C:\"
$Objects = Get-ChildItem $Path -Recurse
$Size = Get-ChildItem $Path -Recurse | Measure-Object -property length -sum
$NumFiles = ($Objects | Where { -not $_.PSIsContainer}).Count
$NumFolders = ($Objects | Where {$_.PSIsContainer}).Count
$Summary = New-Object PSCustomObject -Property #{"Path" = $Path ; "Files" = $NumFiles ; "Folders" = $NumFolders ; "Size in MB" = ([Math]::Round($Size.sum /1MB))}
$Summary | Format-list
To run this on remote computers, I would recommend using New-PsSession to the computer/computers, then Invoke-Command to run the code using the new sessions.
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
}
Please consider the following directory tree:
root
dir1
dir11
x.L01 12kb
x.L02 10kb
dir12
dir122
a.jpg 5kb
b.xls 3kb
c.bmp 3kb
dir2
a.L01 100kb
a.L02 200kb
a.L03 50kb
dir3
dir31
dir4
There are 3 possible cases:
a (sub)dir is empty; root/dir3/dir31 and root/dir4
a (sub)dir contains (only) L0x files, where x is a number; root/dir1/dir11 and root/dir2
a (sub)dir has files, but not of the L0x-kind
The desired output is a custom directory listing with 3 columns:
filepath
filesize
lefcount (see below)
The logic is as follows:
if a (sub)dir is empty, do not list the dir
if a (sub)dir contains (only) L0x files, only list the first one (root/dir1/dir11/x.L01) but count the number of and total filesize of all L01s
if a (sub)dir has other files, list the dir, but count the number of and total filesize of all files
So the example output would be:
path size count
----------------------------------------
root/dir1/dir11/x.L01 22kb 2
root/dir1/dir12/dir122 11kb 3
root/dir2/a.L01 350kb 3
I'm just beginning powershell, and have come up with the following, which is not much but (a) am I going in the right direction? and (b) how to proceed from here?
Get-ChildItem "C:\root" -Recurse |
Foreach-Object {
If ($_.PSIsContainer) {
Get-ChildItem $_.fullname |
Foreach-Object {
Write-Host $_.fullname
}
}
}
Any help would be greatly appreciated!
This can evolve as your needs change. This will create the desired output as a custom object that you can manipulate and export as required.
$rootPath = "c:\temp"
Get-ChildItem $rootPath -Recurse |
Where-Object {$_.PSIsContainer} |
Where-Object {(Get-ChildItem $_.FullName | Where-Object {!$_.PSIsContainer}| Measure-Object | Select-Object -ExpandProperty Count) -gt 0} |
ForEach-Object{
$files = Get-ChildItem $_.FullName
$props = #{
Path = $_.FullName
Size = "{0:N0} KB" -f (($files | Where-Object {!$_.PSIsContainer} | Measure-Object -Sum Length | Select-Object -ExpandProperty Sum) / 1024)
Count = $files | Measure-Object | Select-Object -ExpandProperty Count
}
If($files.Extension -match "L\d\d"){
# These are special files and we are assuming they are alone in the directory
# Change the path
$props.Path = $files | Where-Object {!$_.PSIsContainer} | Select-Object -First 1 | Select-Object -ExpandProperty FullName
}
New-Object -TypeName PSCustomObject -Property $props
} | Select Path,Size,Count
Get all the folders and files recursively for the $rootPath. Filter out all files and empty folders based on their immediate contents. Then build a custom object with all the requested details. If it turns out the L0X files are present then update the path with the first one found.
Currently I assume that all files are of L0X format. If need be we can confirm.
Sample Output
Path Size Count
---- ---- -----
C:\temp\win64 1,092 KB 2
C:\temp\Empy\Stuff\New Text Document - Copy.L01 0 KB 2
How would I use powershell to count the number of files and the number of folders under a folder, emulating the Windows "properties" of that folder?
The FAQ says cross-posting is OK, so the full question can be found at: https://superuser.com/questions/605911/multiple-counts-from-powershell-get-childitem
Basically you need to enumerate all files and folders for a given path and maintain a count of each object type:
$files=$folders=0
$path = "d:\temp"
dir $path -recurse | foreach { if($_.psiscontainer) {$folders+=1} else {$files+=1} }
"'$path' contains $files files, $folders folders"
Edit:
Edited to improve efficiency and stop loops...
This can also be done by using the Measure-Object cmdlet with Get-childItem cmdlet:
gci "C:\" -rec | Measure -property psiscontainer -max -sum | Select `
#{Name="Path"; Expression={$directory.FullName}},
#{Name="Files"; Expression={$_.Count - $_.Sum}},
#{Name="Folders"; Expression={$_.Sum}}
Output:
Path Files Folders
---- ----- -------
C:\Test 470 19