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"}

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)
