Objects are the answer

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.

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

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

This entry was posted in PowerShell v2.0, Scripting and tagged , , , , . Bookmark the permalink.

Comments are closed.