With the help of the Select-Object cmdlet, you can add a calculated property to the output of a PowerShell command. This allows you to enrich the displayed information.

You probably know PowerShell is all about objects. Objects are what make PowerShell great! By nature, all objects have properties, and we can read those properties by various means. The native objects we get back from commands like Get-Process, Get-Service, and a plethora of other commands are usually just fine. But sometimes the properties returned on an object need to change a little bit.

Perhaps you're building a report and need to display a few extra properties to export them correctly. Or maybe you need to tweak an existing property ever so slightly to get it in the format you'd like to see. For these reasons, we have calculated properties in PowerShell.

We can use the calculated properties feature with the Select-Object cmdlet to change or even add additional object properties as PowerShell returns them. Select-Object is a common cmdlet typically used in PowerShell either to show all properties on an object or to limit the default properties shown.

For example, by default, Get-Service will only show a limited number of properties.

Properties that Get-Service returns

Properties that Get-Service returns

If we pipe that same output to Select-Object using the Property parameter, we can show all objects, for example.

Service properties

Service properties

Using Select-Object with the Property parameter allows us to choose which properties to show. However, what if we want to add a custom property to the output or modify an existing property's value? For these situations, we can use calculated properties.

Instead of simple strings like Name, DisplayName, and such, PowerShell represents calculated properties with a hash table containing the name of the property to return and an expression. A script block represents the latter and contains the code to execute and generate the value. For a comparison, here's how we'd display the Name property that Get-Service returns:

Get-Service | Select-Object -Property Name

Here's how we could do the same but by using a calculated property:

Get-Service | Select-Object -Property @{Name = 'Name'; Expression = {$_.Name}}

The example above doesn't make a whole lot of sense because we wouldn't need a calculated property if just displaying the Name property. The example does show how to structure the hash table.

Notice a script block is inside of the Expression key. Inside of that script block, we can reference each object coming from Get-Service with the pipeline variable. For that matter, any object property or method is available for use.

To show a good example of calculated properties, take a look at the default output of Get-Service displayed in the screenshot above. Notice it does not show the path to the EXE the service is controlling. The EXE path is not a property that Get-Service returns natively. But by using calculated properties, we can "add" this property to the output by grabbing that value for each service that comes down the pipeline.

First, we need to figure out where to get the EXE path for each service. To do this, we can dip into the Win32_Service WMI class and gather it using Get-CimInstance. Below, I'm only returning the path for all services and assigning them to a variable. I grab all services ahead of time because if not, I would have had to issue a WMI query for every service, which would be inefficient coding.

$wmiServices = Get-CimInstance -ClassName win32_service -Property Name,PathName

Now that we have all the paths for each service safely stored in a variable, we can now add the code necessary to find the path for each service inside of the Expression script block.

Get-Service | Select-Object -Property *,@{Name = 'PathName'; Expression = { $serviceName = $_.Name; (@($wmiServices).where({ $_.Name -eq $serviceName })).PathName }}

Notice also that I had to still include the * as an element passed to the Property parameter since I still wanted to see all the other properties as well.

Subscribe to 4sysops newsletter!

Calculated properties

Calculated properties

Calculated properties are a great way to manipulate the properties that a command returns. By piping output from commands to Select-Object and using a hash table instead of a string for the Property parameter argument, you're able to return just about any object property you desire!

avataravataravataravatar
10 Comments
  1. Woaow! I am impressed by “@($wmiServices).where…….”

    That’s efficient coding!

    Like I already told you, even if I know the topic,
    I read your posts anyway because I often find some gems inside 😉

    avataravatar
  2. Author
    Adam Bertram (Rank 3) 6 years ago

    I’m glad you’re getting some good stuff out of my content!

    avatar
  3. Kajetan 5 years ago

    Thanks mate, that’s really clean example.

  4. That's really a classic. – Due to unknown reason my cells can't remember the syntax so I keep visiting this site.

    Many thanks for it 🙂

    avatar
  5. Elyoe 3 years ago

    Very nice! Which command would you use if you want to change the Property value?

    For example: Property 'CanStop' is set to 'False', how can I change it to 'True'?

    Regards!

  6. Peter 3 years ago

    Hi

    Are you able to help with the following.
    This works fine in a PowerShell command line but fails when copied into a one liner script

    Get-ADUser -filter {Enabled -eq $True -and PasswordNeverExpires -eq $False} –Properties 'DisplayName', 'msDS-UserPasswordExpiryTimeComputed' | Select-Object -Property 'Displayname',@{Name='ExpiryDate';Expression={[datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}} | sort 

  7. peter 3 years ago

    Further to the confusion

    replacing the username with a real user in the following one liner works both in a command line PowerShell  and in a PowerShell  script

    Get-ADUser "username" -Properties "DisplayName", "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "Displayname",@{Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}} 

    avatar
    • Leos Marek (Rank 4) 3 years ago

      It doenst work for you because the property PasswordNeverExpires is not normally returned by Get-ADUser unless you specifically ask for it via -Properties parameter. So you cant use it in the initial filter.

  8. peter 3 years ago

    ok, got it working in a script
     

    $collection = Get-ADUser  -filter {(Enabled -eq $True) -and (PasswordNeverExpires -eq $False)} 
    foreach ($item in $collection) {
        Get-ADUser "$item" -Properties "DisplayName", "msDS-UserPasswordExpiryTimeComputed" | Select-Object -Property "Displayname",@{Name="ExpiryDate";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")}}     
    }
    

     

    avataravatar

Leave a reply

Please enclose code in pre tags

Your email address will not be published.

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account