Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
February 25, 2025

Extending PowerShell TypeData

In the last newsletter, I demonstrated how to use Add-Member to define new properties and methods on objects. This an alternative to using custom hashtables with Select-Object to define new properties. One benefit of using Add-Member is that you can create script properties that are evaluated each time they are accessed. In order to take advantage of the changes, you need to save the objects.

$jdh = Get-Item c:\scripts\jdh*.ps1 | Foreach-Object {
    $_ | Add-Member -MemberType ScriptProperty -Name "Age" -Value {New-TimeSpan -Start $this.LastWriteTime -End (Get-Date)} -force
    $_ | Add-Member -MemberType ScriptProperty -Name "Computername" -Value {$env:COMPUTERNAME} -force
    $_ | Add-Member -MemberType AliasProperty -Name "Size" -Value Length -Force
    $_ | Add-Member -MemberType AliasProperty -Name "Modified" -Value LastWriteTime -Force
    $_ | Add-Member -MemberType ScriptProperty -Name "SizeKB" -Value {$this.length/1kb} -Force
    #write the updated object to the pipeline
    $_
}

The new members belong to the objects in $jdh. They are not part of the file.

PS C:\> Get-Item c:\scripts\jd*.ps1 | Select Name,SizeKB,Age

Name                       SizeKB Age
----                       ------ ---
jdh-aliases.ps1
JDH-Functions.ps1
jdh-ISEFunctions.ps1
jdh-pscore-prompt.ps1
jdh-psdrives.ps1
jdh-psreadlinehandlers.ps1
jdh-variables.ps1

Instead, they are part of the objects in $jdh.

PS C:\> $jdh | Select Name,SizeKB,Age

Name                       SizeKB Age
----                       ------ ---
jdh-aliases.ps1              3.04 64.20:50:39.4262886
JDH-Functions.ps1           11.65 37.16:56:19.7762253
jdh-ISEFunctions.ps1         1.87 64.20:49:07.4270216
jdh-pscore-prompt.ps1       10.68 212.18:05:34.2850902
jdh-psdrives.ps1             3.54 15.00:32:24.7968166
jdh-psreadlinehandlers.ps1  13.73 314.21:05:18.4272789
jdh-variables.ps1            2.32 37.18:12:25.7863454

The benefit is that I can use these objects with other commands to utilize the new properties.

$jdh |
Sort-Object -Property Age -Descending |
Format-Table -GroupBy Directory -Property Name,SizeKB,Modified,
@{Name="ModifiedAge";Expression = {"{0:dd\.hh\:mm}" -f $_.Age };Alignment="right"},
@{Name="Computername";Expression={$_.Computername};Alignment="center"}
Formatting extended objects
figure 1

However, I want to always have these properties available when I work with files. I don't want to have to add them every time I work with files. I want to extend the System.IO.FileInfo object so that these properties are always available. I can do this with Update-TypeData.

Update-TypeData

I've already shown you that PowerShell uses the Extensible Type System (ETS) to extend objects. These extensions add value to the objects you work with beyond the raw .NET class. The Get-TypeData cmdlet will show you what has been defined for a given type.

PS C:\> Get-TypeData System.IO.FileInfo -outVariable td | Select-Object -ExpandProperty Members

Key                 Value
---                 -----
Mode                System.Management.Automation.Runspaces.CodePropertyData
ModeWithoutHardLink System.Management.Automation.Runspaces.CodePropertyData
VersionInfo         System.Management.Automation.Runspaces.ScriptPropertyData
BaseName            System.Management.Automation.Runspaces.ScriptPropertyData
ResolvedTarget      System.Management.Automation.Runspaces.CodePropertyData
Target              System.Management.Automation.Runspaces.AliasPropertyData
LinkType            System.Management.Automation.Runspaces.CodePropertyData
NameString          System.Management.Automation.Runspaces.CodePropertyData
LengthString        System.Management.Automation.Runspaces.CodePropertyData
LastWriteTimeString System.Management.Automation.Runspaces.CodePropertyData

This is the result from PowerShell 7.5. You might see different results depending on the version of PowerShell you are using. The Members property is a hashtable.

PS C:\> $td.Members["Target"]

ReferencedMemberName MemberType IsHidden Name
-------------------- ---------- -------- ----
LinkTarget                         False Target

I can use these properties with any file system object.

Get-Item $profile | Select-Object -property $($td.members.keys)
PS 7.5 FileInfo Extensions
figure 2
Want to read the full issue?
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.