As I usually do, I was helping out in the forums at ScriptingAnswers.com. A member had several variables that he wanted to show as a group. As is almost always the case, the answer in PowerShell is object. I talk about this all the time in classes, conferences and online chitchat. Let me offer up a script that demonstrates how objects are the answer.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
My business need was to report on files found in a given folder or path. I wanted to get a breakdown of file types showing me the number of each type, their total size and their percentage of all files by count and size.
#requires -version 2.0 Param([string]$path="$env:userprofile\documents") if (Test-Path -path $path) { write-host "Collecting file information for $path" `
-ForegroundColor Green $files=dir $path -recurse -errorAction "SilentlyContinue" |
where {-not $_.PSIsContainer} $stats=$files | Measure-Object -Property Length -sum $grouped=$files | group -property Extension foreach ($group in $grouped) { #measure the total size of each file type $measure=$group.group | measure-object -Property length -sum #calculate % of total size $perSize="{0:P4}" -f ($measure.sum/$stats.sum) #calculate % of total number $perTotal="{0:P4}" -f ($measure.count/$stats.count) #write a custom object to the pipeline new-object psobject -Property @{ Extension=$group.name Total=$group.count TotalSizeMB=[Math]::Round($measure.sum/1mb,2) PercentTotal=$perTotal PercentSize=$perSize Files=$group.group } } #foreach } #if test-path else { Write-Warning "Failed to find $path" }
The script takes a path as a parameter but defaults to your documents folder. Get-Childitem retrieves all files. I’m setting the –errorAction parameter to silentlycontinue to avoid the annoying error messages you get when trying to read protected system folders. The collection of files are then grouped by extension. Each group is then analyzed.
At this point I have a number of pieces of information to display. In a VBScript I would have most like written some message to the screen for each file type. Technically I could do the same thing here but why? Using New-Object I create a new object with properties for all my data. The objects written to the pipeline can be manipulated just like any other object. Let me check my C: drive.
PS C:\> $c=c:\scripts\filestats.ps1 “c:\”
Hmmm…how many different file types are on my computer?
PS C:\> $c.count
1897
Which file types are taking the most space?
PS C:\> $c | sort totalsizeMB -desc | select -first 10 -property * -ExcludeProperty Files | format-table -auto
TotalSizeMB PercentTotal Total Extension PercentSize
----------- ------------ ----- --------- -----------
115692.94 0.0637 % 90 .vmdk 57.8050 %
19559.24 0.0219 % 31 .iso 9.7726 %
14375.12 0.0014 % 2 .vdi 7.1824 %
12440.64 14.8798 % 21018 .dll 6.2159 %
6972.15 2.4778 % 3500 .exe 3.4836 %
6190.48 0.0064 % 9 .wim 3.0930 %
2884.98 0.1373 % 194 .CAB 1.4415 %
2672.56 0.0021 % 3 .m4v 1.3353 %
1424.91 0.0042 % 6 .sav 0.7119 %
1202.12 0.0092 % 13 .mp4 0.6006 %
My custom object even includes a property, files, which itself is a collection of objects. For example, what are the .vdi files?
PS C:\> $c | where {$_.extension -eq ".vdi"} | select -ExpandProperty Files
Directory: C:\VirtualBox\Exchange
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 6/29/2010 1:58 PM 1507336243 ExchangeHDD.vdi
Directory: C:\VirtualBox\R2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 6/21/2010 9:34 PM 41472 ExchangeStore.vdi
The bottom line is that having objects offers tremendous possibilities. So the next time you’re working on a PowerShell problem, know that objects are the answer.
My script was intended as a demonstration but if you’d like a copy