DEV Community

Cover image for PowerShell Measure-Object: Count Lines and Sum Folder Sizes in One Line
arnostorg
arnostorg

Posted on

PowerShell Measure-Object: Count Lines and Sum Folder Sizes in One Line

The PowerShell Measure-Object cmdlet turns a pile of output into a number. How many lines are in this log? How much disk does this folder eat? What's the average order total in this CSV? Instead of opening Excel or writing a loop, you pipe the data in and read the answer off one object.

For the official reference, see Microsoft Learn's Measure-Object.

Count anything

With no parameters, Measure-Object just counts what came down the pipeline:

Get-ChildItem -Path .\logs -File | Measure-Object
Enter fullscreen mode Exit fullscreen mode

You get an object with a Count property (plus empty Sum, Average, and so on). To grab only the number:

(Get-ChildItem -Path .\logs -File | Measure-Object).Count
Enter fullscreen mode Exit fullscreen mode

The short alias is measure, which reads nicely at the end of a one-liner.

Count lines, words, and characters in a file

Text mode works on strings, so pair it with Get-Content:

Get-Content -Path .\notes.md | Measure-Object -Line -Word -Character
Enter fullscreen mode Exit fullscreen mode

Output looks like this:

Lines Words Characters Property
----- ----- ---------- --------
   42   613       3920
Enter fullscreen mode Exit fullscreen mode

One gotcha worth knowing: -Line skips empty lines. If you need the raw line count including blanks, count the array instead:

(Get-Content -Path .\notes.md).Count
Enter fullscreen mode Exit fullscreen mode

Use -IgnoreWhiteSpace with -Character when you want characters without spaces and tabs.

Sum the size of a folder

This is the one people bookmark. Files have a Length property in bytes, so sum it:

Get-ChildItem -Path .\downloads -File -Recurse |
  Measure-Object -Property Length -Sum
Enter fullscreen mode Exit fullscreen mode

Bytes are hard to read, so divide by PowerShell's built-in size constants:

$total = (Get-ChildItem -Path .\downloads -File -Recurse |
  Measure-Object -Property Length -Sum).Sum

'{0:N2} MB' -f ($total / 1MB)
'{0:N2} GB' -f ($total / 1GB)
Enter fullscreen mode Exit fullscreen mode

Keep -File in there. Folders don't have a Length, so leaving them in the pipeline only adds noise.

Min, max, and average in one pass

Ask for several statistics at once:

Get-ChildItem -Path .\logs -File |
  Measure-Object -Property Length -Minimum -Maximum -Average -Sum
Enter fullscreen mode Exit fullscreen mode

That tells you in a single command whether one runaway log is hiding among small ones. On PowerShell 7 you can use -AllStats to get every statistic, including standard deviation, without listing each switch. Windows PowerShell 5.1 doesn't have it, so spell them out there.

Measure a CSV column (and the text trap)

Import-Csv gives you objects whose properties are all strings. For sums and averages it's safest to cast to a number first so nothing gets compared as text:

Import-Csv -Path .\orders.csv |
  ForEach-Object { [double]$_.Total } |
  Measure-Object -Sum -Average -Maximum
Enter fullscreen mode Exit fullscreen mode

If a column can contain N/A, the cast throws on the first bad row. Blanks are sneakier: [double]'' quietly becomes 0 and drags your average down. Filter both out before the cast:

Import-Csv -Path .\orders.csv |
  Where-Object { $_.Total -ne '' -and $null -ne ($_.Total -as [double]) } |
  ForEach-Object { [double]$_.Total } |
  Measure-Object -Sum -Average
Enter fullscreen mode Exit fullscreen mode

Count matches instead of reading them

When you only care how many errors a log has, not what they say, count the matches:

(Select-String -Path .\app.log -Pattern 'ERROR' | Measure-Object).Count
Enter fullscreen mode Exit fullscreen mode

Point it at many files and you get a total across all of them:

(Select-String -Path .\logs\*.log -Pattern 'timeout' | Measure-Object).Count
Enter fullscreen mode Exit fullscreen mode

Practical ops examples

Which file types are eating the disk?

Get-ChildItem -Path .\project -File -Recurse |
  Group-Object -Property Extension |
  ForEach-Object {
    [pscustomobject]@{
      Extension = $_.Name
      Files     = $_.Count
      MB        = [math]::Round(($_.Group | Measure-Object -Property Length -Sum).Sum / 1MB, 2)
    }
  } |
  Sort-Object -Property MB -Descending |
  Select-Object -First 10
Enter fullscreen mode Exit fullscreen mode

Alert when a log folder grows too big:

$limitMB = 500
$sizeMB = (Get-ChildItem -Path C:\Apps\MyService\logs -File |
  Measure-Object -Property Length -Sum).Sum / 1MB

if ($sizeMB -gt $limitMB) {
  Write-Warning ('Logs are {0:N0} MB (limit {1} MB)' -f $sizeMB, $limitMB)
}
Enter fullscreen mode Exit fullscreen mode

Sanity-check an export before you send it:

$rows = (Import-Csv -Path .\export.csv | Measure-Object).Count
if ($rows -eq 0) {
  Write-Error 'Export is empty, not sending'
  return
}
"Export has $rows rows"
Enter fullscreen mode Exit fullscreen mode

Quick checklist

  • How many items? Pipe to Measure-Object and read .Count.
  • How many lines or words in a text file? Use -Line -Word -Character after Get-Content (blank lines aren't counted by -Line).
  • How big is a folder? Use Get-ChildItem -File -Recurse | Measure-Object Length -Sum, then divide by 1MB or 1GB.
  • Need min, max, or average? Add -Minimum -Maximum -Average (or -AllStats on PowerShell 7).
  • Numbers from a CSV? Cast to [double] before measuring.
  • How many errors? Use Select-String piped to Measure-Object.

Practice it live

CMD Master is a free online interactive learning platform for the command line. You can practice PowerShell pipelines like Measure-Object in a live browser terminal with instant feedback, no install or VM needed. It also covers Windows CMD and Bash, most lessons are free, and premium unlocks the deeper paths. If you're newer to the shell, start with the free interactive command line lessons on CMD Master.

Top comments (0)