Skip to content

jdhitsolutions/PSTypeExtensionTools

Repository files navigation

PSTypeExtensionTools

PSGallery Version PSGallery Downloads

This PowerShell module contains commands that make it easier to work with type extensions. Many of these commands are wrappers for built-in tools like Get-TypeData or Update-TypeData. This module should work in Windows PowerShell 5.1 and PowerShell 7.x. Although some of the sample type extensions require a Windows platform.

Installation

You can install the current release from the PowerShell Gallery:

Install-PSResource PSTypeExtensionTools

The module contains these commands.

Name Alias Synopsis
Add-PSTypeExtension Set-PSTypeExtension,atex Add a new type extension.
Export-PSTypeExtension etex Export type extensions to a file.
Get-PSType Get the type name for a given object.
Get-PSTypeDataPreview Preview the type extension settings in a ps1xml file.
Get-PSTypeExtension gtex Get selected type extensions.
Import-PSTypeExtension itex Import type extension definitions.
New-PSPropertySet Create a new property set ps1xml file.

Why You Want to Use This Module

Let's say you want to update a number object, but you have no idea what the type name is. Once you have read help for the commands in this module, you could run a PowerShell command like this:

123 | Get-PSType | Add-PSTypeExtension -MemberType ScriptProperty -MemberName SquareRoot -Value {[math]::Sqrt($this)}

Use $this to reference the object instead of $_. Now you can get the new property.

PS C:\> $x = 123
PS C:\> $x.SquareRoot
11.0905365064094

Once you know the type name, you can add other type extensions.

Add-PSTypeExtension -TypeName system.int32 -MemberType ScriptProperty -MemberName Squared -value {$this*$this}
Add-PSTypeExtension -TypeName system.int32 -MemberType ScriptProperty -MemberName Cubed -value {[math]::Pow($this,3)}
Add-PSTypeExtension -TypeName system.int32 -MemberType ScriptProperty -MemberName Value -value {$this}
Add-PSTypeExtension -TypeName system.int32 -MemberType ScriptMethod -MemberName GetPercent -value {Param([int32]$Total,[int32]$Round=2) [math]::Round(($this/$total)*100,$round)}

Here's how it might look:

PS C:\> $x = 38
PS C:\> $x | select *

      SquareRoot Squared Cubed Value
      ---------- ------- ----- -----
6.16441400296898    1444 54872    38

PS C:\> $x.GetPercent(50)
76
PS C:\> $x.GetPercent(100)
38
PS C:\> $x.GetPercent(110,4)
34.5455

Go GUI

As an alternative to the command-line, you can use the native Show-Command cmdlet to display a graphical interface.

Show-Command Add-PSTypeExtension

Add via GUI

Clicking Run will insert this code at your prompt.

Add-PSTypeExtension -MemberName ToTitleCase -MemberType ScriptMethod -TypeName System.String -Value { (Get-Culture).TextInfo.ToTitleCase($this.ToLower())}

If you like this extension, you can export it and re-import it later.

Get Type Extensions

To see current type extensions, you can use Get-PSTypeExtension. You can choose to see all extensions or selected ones by member name. CodeProperty extensions are hidden by default.

PS C:\> Get-PSTypeExtension system.int32

   TypeName: System.Int32

Name       Type           Value
----       ----           -----
SquareRoot ScriptProperty  [math]::Sqrt($this)
Squared    ScriptProperty  $this*$this
Cubed      ScriptProperty  [math]::Pow($this,3)
Value      ScriptProperty  $this
GetPercent ScriptMethod   Param([int32]$Total,[int32]$Round=2) [math]::Round(($this/$total)*100,$round)

If you always want these extensions, you would have to put the commands into your PowerShell profile script. Or you can export the extensions to a JSON or XML file. You can either export all members or selected ones, which is helpful if you are extending a type that already has type extensions from PowerShell.

Get-PSTypeExtension system.int32 |
Export-PSTypeExtension -TypeName system.int32 -Path c:\work\int32-types.json

In your PowerShell profile scrip,t you can then re-import the type extension definitions.

Import-PSTypeExtension -Path C:\work\int32-types.json

Property Sets

In addition to custom properties, PowerShell also has the idea of a propertyset. This allows you to reference a group of properties with a single name.

Let's say you have loaded the sample 'System.IO.FileInfo` type extensions from this module.

Import-PSTypeExtension -Path $PSTypeSamples\fileinfo-extensions.json

You could write a command like this:

dir c:\work -file | Select-Object Name,Size,LastWriteTime,Age

Or you could create a custom property set. These have to be defined in ps1xml files. The New-PSPropertySet simplifies this process.

New-PSPropertySet -Typename System.IO.FileInfo -Name FileAge -Properties Name,Size,LastWriteTime,Age -FilePath d:\temp\FileInfo.types.ps1xml

I've included the file in the Samples folder.

PS C:\> Update-TypeData $PSTypeSamples\FileInfo.types.ps1xml
PS C:\> dir c:\work -file | Select-Object FileAge

Name                          Size    LastWriteTime            Age
----                          ---- -  -----------              ---
a.dat                            42   2/12/2024 5:36:55 PM     23.17:27:21
a.txt                         14346   12/31/2023 9:10:15 AM    67.01:54:00
a.xml                        171394   12/31/2023 12:15:44 PM   66.22:48:32
aa.ps1                        28866   12/31/2023 9:13:16 AM    67.01:51:00
aa.txt                        28866   12/31/2023 9:11:18 AM    67.01:52:58
about.json                    16455   2/27/2024 10:11:03 AM    09.00:53:12
about_ADReportingTools         1688   3/4/2024 7:37:01 PM      03.15:27:14
b.csv                          1273   11/13/2023 12:11:35 PM   114.22:52:40
...

If your property set is using custom properties, you need to load them into your PowerShell session before you can use the property set.

Create ps1xml Files

The Export-PSTypeExtension command will also export extensions to a properly formatted .ps1xml file. This can be useful when building type extension files for a module where you want to use the traditional ps1xml form. You can also import these types of files with Update-TypeData with the -AppendPath or -PrependPath parameters.

When exporting to .ps1xml file, Export-PSTypeExtension has a dynamic parameter, Append. This allows you to combine multiple type extensions into a single file. If you intend to use a property set, create that file first. Then append your custom type extensions to that file.

Here's how this might look.

First, create a property set file.

New-PSPropertySet -Typename System.IO.FileInfo -Name TimeSet -Properties "Name","Length","CreationTime","LastWriteTime" -FilePath c:\work\file.types.ps1xml

I'll define a few type extensions.

Add-PSTypeExtension -TypeName System.IO.FileInfo -MemberType AliasProperty -MemberName Size -Value Length
Add-PSTypeExtension -TypeName System.IO.FileInfo -MemberType ScriptProperty -MemberName ModifiedAge -Value {New-TimeSpan -Start $this.LastWriteTime -End (Get-Date)}

I'll even add a second property set to the same file using these new extensions.

Export-PSTypeExtension -TypeName System.IO.FileInfo -MemberName Size,ModifiedAge -Path c:\work\file.types.ps1xml -append

I'll end up with this file:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file was created with New-PSPropertySet from the
PSTypeExtensionTools module which you can install from
the PowerShell Gallery.

Use Update-TypeData to append this file in your PowerShell session.

Created 03/09/2024 15:27:56
-->
<Types>
  <Type>
    <Name>System.IO.FileInfo</Name>
    <Members>
      <PropertySet>
        <Name>TimeSet</Name>
        <ReferencedProperties>
          <Name>Name</Name>
          <Name>Length</Name>
          <Name>CreationTime</Name>
          <Name>LastWriteTime</Name>
        </ReferencedProperties>
      </PropertySet>
      <PropertySet>
        <Name>Age</Name>
        <ReferencedProperties>
          <Name>Name</Name>
          <Name>Size</Name>
          <Name>LastWriteTime</Name>
          <Name>ModifiedAge</Name>
        </ReferencedProperties>
      </PropertySet>
      <AliasProperty>
        <Name>Size</Name>
        <ReferencedMemberName>Length</ReferencedMemberName>
      </AliasProperty>
      <ScriptProperty>
        <Name>ModifiedAge</Name>
        <GetScriptBlock>New-TimeSpan -Start $this.lastwritetime -End (Get-Date)</GetScriptBlock>
      </ScriptProperty>
    </Members>
  </Type>
</Types>

In PowerShell, I can load this file and use it.

PS C:\> Update-TypeData c:\work\file.types.ps1xml
PS C:\> Get-ChildItem -path c:\work\*.csv |
Sort-Object -property size -Descending | Select Age

Name              Size LastWriteTime          ModifiedAge
----              ---- -------------          -----------
updates.csv    4021821 11/14/2023 9:00:48 AM  115.06:45:35.2595780
part5.csv         7332 2/27/2024 6:10:11 PM   9.21:36:12.4672428
ipperf.csv        5008 11/4/2023 11:36:20 AM  125.04:10:03.4641251
localusers.csv    1480 2/27/2024 4:39:32 PM   9.23:06:51.7431393
b.csv             1273 11/13/2023 12:11:35 PM 116.03:34:48.0298279
foo.csv           1077 11/13/2023 12:40:04 PM 116.03:06:19.3069112
y.csv              524 11/19/2023 2:11:44 PM  110.01:34:39.0826388
yy.csv             524 12/1/2023 11:28:03 AM  98.04:18:20.7080948
c.csv              334 11/13/2023 11:58:15 AM 116.03:48:08.3898463
a.csv                0 12/1/2023 11:30:55 AM  98.04:15:27.9106911

I can put the Update-TypeData command in my PowerShell profile to always have these extensions. Or I could share the file.

Previewing Type Extensions

Depending on the file you are using to update type data, there are a few options to preview the type extensions before you import them. If you have exported settings to a JSON or XML file using Export-PSTypeExtension, you can use the Preview parameter of Import-PSTypeExtension command to see the type extensions before they are applied.

PS C:\> Import-PSTypeExtension $PSTypeSamples\stringtypes.json -Preview

   TypeName: System.String

MemberType     MemberName  Value
----------     ----------  -----
AliasProperty  Size        Length
ScriptMethod   IsIPAddress $this -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$"
ScriptMethod   Randomize   ($this.ToCharArray() | get-random -Count $this.length) -join ""
ScriptMethod   Reverse     for ($i=$this.length;$i -ge 0;$i--) {…
ScriptMethod   Reverse     ($this.ToCharArray())[-1..-$this.length] -join ""
ScriptProperty IsEmail     $this -match '^\S+@([\w-]+)\.(com|edu|org|net)$'

PS C:\> Import-PSTypeExtension $PSTypeSamples\measureinfo.xml -Preview

   TypeName: Microsoft.PowerShell.Commands.GenericMeasureInfo

MemberType     MemberName Value
----------     ---------- -----
ScriptProperty SumGB      [math]::Round($this.sum/1gb,4)
ScriptProperty SumKB      [math]::Round($this.sum/1kb,4)
ScriptProperty SumMB      [math]::Round($this.sum/1mb,4)

The Get-PSTypeDataPreview command will display the type extensions in a ps1xml file. This is useful if you want to see what type extensions are defined in a file before you import them.

If you have a ps1xml file, you can use the Get-PSTypeDataPreview command to see the type extensions.

GetPSTypeDataPreview

The default output uses custom formatting to display type extensions using ANSI color sequences. Or you can use the object directly.

PS C:\> $a = Get-PStypeDataPreview $PSTypeSamples\process.types.ps1xml
PS C:\> $a | Select-Object *

TypeName       : System.Diagnostics.Process
AliasProperty  : {@{Name=Computername; Reference=MachineName}, @{Name=Started; Reference=StartTime}}
NoteProperty   : @{Name=Comment; Value=Type extended with PSTypeExtensionTools}
ScriptProperty : @{Name=RunTime; Get=(Get-Date) - $this.StartTime; Set=}
PropertySet    : {@{Name=PSRun; Properties=System.Object[]}, @{Name=RunInfo; Properties=System.Object[]}}
Path           : C:\scripts\PSTypeExtensionTools\samples\process.types.ps1xml

PS C:\> $a.PropertySet

Name    Properties
----    ----------
PSRun   {ID, Name, WS, StartTime...}
RunInfo {ID, Name, StartTime, RunTime...}

I Want to Try

You can find sample and demonstration type extension exports in the Samples folder. When you import the module, this location is saved to a global variable, $PSTypeSamples.

PS C:\> Get-ChildItem $PSTypeSamples

    Directory: C:\scripts\PSTypeExtensionTools\samples

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
a---          10/11/2024  4:52 PM            762 cimlogicaldisk-extensions.json
a---          10/11/2024  4:32 PM            265 datetime-extensions.json
a---          10/11/2024  4:32 PM            490 eventlog-type.json
a---           6/24/2025 12:02 PM           2608 fileinfo-extensions.json
a---           6/24/2025  4:44 PM            728 fileinfo.types.ps1xml
a---          10/11/2024  4:32 PM            901 int32-types.json
a---          10/11/2024  4:32 PM           1318 measure-extensions.json
a---           6/24/2025 11:48 AM           1066 measureinfo.xml
a---           6/24/2025 11:33 AM           1176 msft_volume-extensions.json
a---           6/24/2025  1:56 PM            656 mydatetime.types.ps1xml
a---           6/24/2025  1:56 PM            444 process-types.xml
a---           6/24/2025  2:14 PM           1555 process.types.ps1xml
a---          10/11/2024  4:33 PM            944 README.md
a---          10/11/2024  4:32 PM           1246 stringtypes.json
a---           6/24/2025 11:30 AM           3024 vm-extensions.json

PS C:\> Import-PSTypeExtension $PSTypeSamples\measure-extensions.json -Verbose
VERBOSE: Starting: Import-PSTypeExtension
VERBOSE: Importing file C:\scripts\PSTypeExtensionTools\samples\measure-extensions.json
VERBOSE: Processing ScriptProperty : SumKB
VERBOSE: Creating scriptblock from value
VERBOSE: Performing the operation "Adding ScriptProperty SumKB" on target "Microsoft.PowerShell.Commands.GenericMeasureInfo".
VERBOSE: Processing ScriptProperty : SumMB
VERBOSE: Creating scriptblock from value
VERBOSE: Performing the operation "Adding ScriptProperty SumMB" on target "Microsoft.PowerShell.Commands.GenericMeasureInfo".
VERBOSE: Processing ScriptProperty : SumGB
VERBOSE: Creating scriptblock from value
VERBOSE: Performing the operation "Adding ScriptProperty SumGB" on target "Microsoft.PowerShell.Commands.GenericMeasureInfo".
VERBOSE: Ending: Import-PSTypeExtension

PS C:\> Get-ChildItem D:\VMDisks\ -file -recurse | Measure-Object -property length -sum |
Select-Object Count,SumGB

Count   SumGB
-----   -----
    4 50.2031

This project was first described at http://jdhitsolutions.com/blog/powershell/5777/a-powershell-module-for-your-type-extensions

There is an about help topic you can read:

help about_PSTypeExtensionTools

About

A set of PowerShell tools for working with type extensions.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published