powershell folder stats
I keep all modules of our system in one dir (e.g. All\ModuleA; All\ModuleB
). I want to see what types of files are most numerous and take up the most space开发者_如何学Python, by module. So, I'd like output along the lines of:
ModName,java-count,java-size,xml-count,xml-size,png-count,png-size...
ModuleA,30,0.2,100,2.3,0,0,...
ModuleB,21,0.1,20,0.7,1,1.2
Not all modules have files of all types, so this will only work if I list all types for all module (with lots of zeros). I have something that almost works, but it's hideous, verbose and inefficient. I'm sure someone can help me see the light :-) (which, by the way, can be a piece of freeware software that does this out of the box; I only chose to do this in powershell out of interest).
thanks
The basic group
, select
and sort
cmdlets should do the trick:
Get-ChildItem . | Where {!$_.PSIsContainer} | Group Extension |
Select Count, Name, @{n='Size';e={($_.Group | Measure Length -Sum).Sum}} |
Sort Size -desc | Format-Table -auto
I'd like to see your solution, because after very short (incomplete) solution I came up with
$dir = 'c:\windows\system32'
function Extension($item) {
$e = $_.Extension.Trim('.')
if ($e) { $e } else { '-empty-' }
}
# gets info about the folder
# returns 2 hashtables - one with sizes, one with counts (keys are extensions)
function GetInfo($dir) {
$counts, $lengths =
gci $dir -rec | ? { !$_.PsIsContainer } |
% -begin {
$c=@{}; $s=@{}} `
-process {
$ext = Extension $_
$s[$ext] += $_.Length
$c[$ext] += 1 } `
-end {$c, $s}
@{Counts = $counts; Lengths = $lengths }
}
# $res.Names holds all the property names (extensions) that will be used
# might be possible to use global variable, but...
$res =
gci $dir |
? { $_.PsIsContainer } |
% { new-object psobject -prop (@{Name=$_.Name} + (GetInfo $_.FullName)) } |
% -beg { $names = @{}; $obj = @()} `
-process { $_.Lengths.Keys|%{ $names[$_] = $_ }
$obj += $_
} `
-end { @{Names=@($names.keys.GetEnumerator()); Dirs=$obj } }
# Create new objects from the partial info
$result = foreach ($dir in $res.Dirs) {
$ret = New-Object PsObject -prop @{Name = $dir.Name}
foreach ($name in $res.Names) {
$ret |
# if there is no key in $dir.Counts or $dir.Lengths, 0 is returned
Add-Member NoteProperty ($name+"_count") -value ([int]$dir.Counts[$name]) -pass |
Add-Member NoteProperty ($name+"_size") -value ([int]$dir.Lengths[$name])
}
$ret
}
The code is commented so it should be clear what's going on. The tricky part was to add properties about extensions to each object even though the directory doesn't have any file with the extension. (the list of extensions is not complete until it traverses all the directories).
Then you can see that the result is regular PsObject
:
PS> $result | ft Name,dll_count,dll_size,exe_count,exe_size,bat_count,bat_size -auto
Name dll_count dll_size exe_count exe_size bat_count bat_size
---- --------- -------- --------- -------- --------- --------
0409 0 0 0 0 0 0
1033 1 17760 0 0 0 0
AdvancedInstallers 3 2312192 0 0 0 0
ar-SA 0 0 0 0 0 0
BestPractices 0 0 0 0 0 0
bg-BG 0 0 0 0 0 0
catroot 0 0 0 0 0 0
catroot2 0 0 0 0 0 0
com 1 201216 2 24064 0 0
config 0 0 0 0 0 0
Not sure if this is any less "hideous, verbose, and inefficient" than what your using, but this is how I'd approach getting the stats on the file types in a given folder:
$ext_count = @{}
$ext_size = @{}
gci c:\windows\system32 |
where {-not $_.psiscontainer} |
foreach-object {
$ext_count[$_.extension] ++
$ext_size[$_.extension] += [int]$_.length
}
$ext_count
$ext_size
After that, it's just a matter of sorting out the one's your interested in.
精彩评论