Columns You Make Yourself: Calculated Properties
A calculated property is a column you add to Select-Object yourself, written as a hashtable with a Name for the heading and an Expression that works the value out for each object, such as a file's size in megabytes, rounded with [math]::Round.
Journeyman · PowerShell · Operating System · Updated
After this lesson you can
- Add a column of your own to Select-Object with a calculated property, @{ Name = …; Expression = { … } }
- Show sizes in KB or MB with a calculated property, rounded with [math]::Round
Key takeaways
@{ Name = 'SizeMB'; Expression = { $_.Length / 1MB } }is a column of your own: a heading, and a recipe that runs for each object.- Read it in pieces:
@{ }is a hashtable,Nameis the heading,;separates the two parts, andExpressionis a script block with$_as this item. [math]::Round($_.Length / 1MB, 1)rounds to one decimal place. PowerShell 7.6's tables show two places, but the number itself is rounded.- The new column is a real property, so Sort-Object can sort by it.
Someone asks how big the graduation video is, and PowerShell says 2867200. That's bytes, and nobody reads bytes. File Explorer shows "2,800 KB", which is closer, but you want "2.7 MB", or a report for your manager with a size column people can read at a glance. PowerShell's columns are the properties an object already has. This lesson shows how to add a column of your own, worked out from the others: the way an IT tech writes a disk report, or a data analyst adds a "total" column to an export.
This lesson uses the drive folder from The Pipeline: |. Run that lesson's practice-drive lines first if you need to, then Set-Location ~\terminal-practice\drive.
A heading and a recipe
Select-Object picks columns by name, as in Picking Columns: Select-Object. In place of a name, you can give it a small card with two lines on it: the column's heading, and a recipe that works out the value for each object:
Get-ChildItem videos | Select-Object Name, @{ Name = 'SizeMB'; Expression = { $_.Length / 1MB } }
Name SizeMB
---- ------
birthday-party.mp4 1.46
cat-and-the-cucumber.mp4 0.68
graduation.mp4 2.73
Read the card one piece at a time:
@{ … }(read "at-sign braces") is a hashtable: a list of labels, each with a value, like the lines on a recipe card.Name = 'SizeMB'is the column's heading.=is read "is": "Name is SizeMB".;(a semicolon) separates the card's two lines.Expression = { $_.Length / 1MB }is the recipe: a script block that runs once for each file, with$_as this item, as in Doing Something to Each: ForEach-Object. Here it divides the file's Length by one megabyte.
A column made this way is called a calculated property. Forget the ; and PowerShell stops with Unexpected token 'Expression': it read Name = 'SizeMB' and didn't expect another word.
Rounding: [math]::Round
PowerShell 7.6's tables show two decimal places, but the number underneath is longer. Format-List, from Tables and Lists: Format-Table and Format-List, shows all of it:
Get-ChildItem videos | Select-Object Name, @{ Name = 'SizeMB'; Expression = { $_.Length / 1MB } } | Format-List
Name : birthday-party.mp4
SizeMB : 1.46484375
Name : cat-and-the-cucumber.mp4
SizeMB : 0.68359375
Name : graduation.mp4
SizeMB : 2.734375
Write that to a file and every digit goes with it. [math]::Round rounds the number itself. [math] is a toolbox of math that comes with .NET, the library PowerShell is built on, and :: (read "colon colon") opens it. Give Round the number, a comma, and how many decimal places to keep:
Get-ChildItem videos | Select-Object Name, @{ Name = 'SizeMB'; Expression = { [math]::Round($_.Length / 1MB, 1) } }
Name SizeMB
---- ------
birthday-party.mp4 1.50
cat-and-the-cucumber.mp4 0.70
graduation.mp4 2.70
The table still shows two places, but each value is now 1.5, 0.7 and 2.7: Format-List would show them that way. Windows PowerShell 5.1's tables show 1.5 and 1.46484375 as they are. For kilobytes, divide by 1KB instead.
Space by file type, in one table
Counting and Grouping: Measure-Object and Group-Object measured one kind of file at a time and promised a whole table. Here it is, with the pipeline over four lines (each line ends with |, so PowerShell waits for the next):
Get-ChildItem -Recurse -File |
Group-Object Extension |
Select-Object Name, Count, @{ Name = 'SizeMB'; Expression = { [math]::Round(($_.Group | Measure-Object Length -Sum).Sum / 1MB, 1) } } |
Sort-Object SizeMB -Descending
Name Count SizeMB
---- ----- ------
.mp4 3 4.90
.mp3 3 3.10
.exe 1 2.20
.zip 1 1.90
.jpg 2 1.80
.tmp 1 1.10
.pdf 2 1.00
.png 2 0.60
.docx 1 0.00
.txt 1 0.00
.xlsx 1 0.00
Here $_ is one pile from Group-Object, and $_.Group is its files. The recipe adds up their Length, turns it into megabytes and rounds it. The three small documents round to 0.0: each is under a twentieth of a megabyte. Because SizeMB is now a real property, Sort-Object sorts by it. The videos are what's filling this drive.
Shorter keys, and other columns
Name and Expression can be cut down to n and e (and Label, or l, works in place of Name), so you'll see cards like this in other people's commands:
Get-ChildItem documents | Select-Object Name, @{ n = 'SizeKB'; e = { [math]::Round($_.Length / 1KB) } }
Name SizeKB
---- ------
budget-2026.xlsx 48.00
resume.docx 36.00
shopping-list.txt 0.00
tax-return-2025.pdf 420.00
The recipe can use anything an object knows, not only sizes. @{ Name = 'Folder'; Expression = { $_.Directory.Name } } adds the name of the folder each file is in.
Try it. List the five biggest files on the drive with their Name and a SizeKB column rounded to whole kilobytes. Then add a Folder column.
Check yourself
2 questions to try on the lesson page.
So what
When the facts an object has aren't quite the ones you need, make your own column: a heading, and a recipe for each item.