Extending Object Types and Formatting
Windows PowerShell™ is an object-based scripting environment where objects are passed through the pipeline. Consequently, as you design your own cmdlets, providers, or applications, you may need to define your new object types, extend existing object types, or modify how an object is displayed by the hosting application.
Note
Windows PowerShell provides a mechanism for showing custom views of existing .NET objects, referred to as "adaptive views", and a mechanism for adding members to existing objects. For more information about adaptive views and extended objects, see Windows PowerShell Object Concepts.
After completing the functionality of a new cmdlet, provider, or application, you must document the types and the formatting of any extended or new .NET objects that have been defined. The topics in this section include:
Defining Object Types
Defining Object Formatting
Defining Object Types
Windows PowerShell uses XML-based files to define object types. The types.ps1xml file that is installed with Windows PowerShell, defines the object types that are used by Windows PowerShell cmdlets, providers, and the default hosting application powershell.exe. In this default Types file, each type is defined in a Type node, which uses the <Type></Type> delimiters. When defining your own object types or any extensions for existing objects, you will need to create a customized Types file, taking definitions from the default types file, as required.
Note
Never change the default Types.ps1xml file shipped with Windows PowerShell as that could cause unexpected behavior by Windows PowerShell.
Preparing a Custom Types File
Use this procedure to create your own custom types file.
Create a YourProductName.Types.ps1xml text file in the same directory as the default types file.
Open the file and create the root Types node, using the <Types></Types> delimiters.
Customize the Types node as required, adding a Type node for each new or extended type that your cmdlets, providers, or applications define.
The following topics provide details of customization of the file for standard members, data members, and object methods.
Defining Standard Members
For each type, you can define the set of standard members that you want displayed for an object. To do this you create a MemberSet node with the name the PSStandardMembers. In that node, you can define the following three kinds of default members.
DefaultDisplayProperty member. This is the single property used for the display of headers. It is a NoteProperty node with the name DefaultDisplayProperty. The Value element is the name of the referenced property for which the value is retrieved.
DefaultDisplayPropertySet. This is the default set of properties used for display. It is a PropertySet node with the name DefaultDisplayPropertySet. The node contains the set of names for the referenced properties to display for the object.
DefaultKeyPropertySet. This is the primary property set used when sorting objects. It is a PropertySet node with the name DefaultKeyPropertySet. The value is the set of names for default properties to use as a key for the object. The key that is represented is not necessarily unique.
Here is a template that can be used to start defining the standard members. For an example of of how Windows PowerShell does this, see the Types.ps1xml file shipped with Windows PowerShell.
<Type>
<Name>MyNamespace.MyType</Name>
<Members>
<MemberSet>
<Name>PsStandardMembers</Name>
<Members>
<NoteProperty>
<Name>DefaultDisplayProperty</Name>
<Value>ReferencedPropertyName</Value>
</NoteProperty>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<PropertySet>
<ReferencedProperties>
<Name>ReferencedPropertyName1</Name>
<Name>ReferencedPropertyName2</Name>
<ReferencedProperties>
</PropertySet>
<PropertySet>
<Name>DefaultKeyPropertySet</Name>
<ReferencedProperties>
<Name>ReferencedPropertyName1</Name>
<ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>
</Members
</Type>
Defining Object Properties
When defining custom .NET objects, you can define properties in your code, and then reflect those members in your Types file. To do this, create a MemberSet node for the properties of an object. Ensure that these members map directly to the parameters of cmdlets that will use the object. This mapping allows the object to be easily and consistently pipelined by the Windows PowerShell runtime.
Here is a template that can be used to start defining the properties. Notice that this template includes an AliasProperty node for defining aliases for a property. For an example of of how Windows PowerShell does this, see the Types.ps1xml file shipped with Windows PowerShell.
<Members>
<ScriptProperty>
<Name>PropertyName</Name>
<GetScriptBlock></GetScriptBlock>
</ScriptProperty>
<AliasProperty>
<Name>Alias</Name>
<ReferencedMemberName>AliasedProperty</ReferencedMemberName>
</AliasProperty>
</Members>
Defining Object Methods
When defining custom .NET objects, you can define their methods in your code, and then reflect those members in your Types file. You can use the CodeMethod node in the types file to define any methods for a custom .NET object.
Here is a template that can be used to start defining methods. For an example of of how Windows PowerShell does this, see the Types.ps1xml file shipped with Windows PowerShell.
<Members>
<CodeMethod>
<Name>ToString</Name>
<CodeReference>
<TypeName></TypeName>
<MethodName></MethodName>
</CodeReference>
</CodeMethod>
</Members>
Sample Type Node
The following is a sample Type node for the Process object passed by several of the cmdlet samples in this guide. In this case, you are setting only the members that you want to display by default for these objects.
<Type>
<Name>System.Diagnostics.Process</Name>
<Members>
<MemberSet>
<Name>PsStandardMembers</Name>
<Members>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<ReferencedProperties>
<Name>Handles</Name>
<Name>CPU</Name>
<Name>Id</Name>
<Name>Name</Name>
</ReferencedProperties>
</PropertySet>
<NoteProperty>
<Name>DefaultDisplayProperty</Name>
<Value>Name</Value>
</NoteProperty>
<PropertySet>
<Name>DefaultKeyPropertySet</Name>
<ReferencedProperties>
<Name>Name</Name>
<Name>Id</Name>
</ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>
<AliasProperty>
<Name>Name</Name>
<ReferencedMemberName>ProcessName</ReferencedMemberName>
</AliasProperty>
<AliasProperty>
<Name>Handles</Name>
<ReferencedMemberName>Handlecount</ReferencedMemberName>
</AliasProperty>
<ScriptProperty>
<Name>CPU</Name>
<GetScriptBlock>$this.TotalProcessorTime.
TotalSeconds</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>Path</Name>
<GetScriptBlock>$this.Mainmodule.FileName</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>Company</Name>
<GetScriptBlock>$this.Mainmodule.FileVersionInfo.
CompanyName</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>FileVersion</Name>
<GetScriptBlock>$this.Mainmodule.FileVersionInfo.
FileVersion</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>ProductVersion</Name>
<GetScriptBlock>$this.Mainmodule.FileVersionInfo.
ProductVersion</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>Description</Name>
<GetScriptBlock>$this.Mainmodule.FileVersionInfo.
FileDescription</GetScriptBlock>
</ScriptProperty>
<ScriptProperty>
<Name>Product</Name>
<GetScriptBlock>$this.Mainmodule.FileVersionInfo.
ProductName</GetScriptBlock>
</ScriptProperty>
</Members>
</Type>
Loading the New Types File
You can load your custom Types file using the Update-TypeData cmdlet as shown here.
PS> update-typedata -prepend YourProductName.Types.ps1xml
Testing your New Types File
To verify that your object types have been properly extended, try several commands as a test. Here is an example testing our sample Types file using the Get-Proc cmdlet.
PS> gps | select-object -first 5
Handles CPU Id Name
------- --- -- ----
269 0.050072 3956 alg
58 0.1301872 740 ati2evxx
61 0.1101584 1708 ati2evxx
50 0.1402016 868 BTTray
38 0.0100144 1888 twdins
PS> gps | sort-object | select-object -first 5
Handles CPU Id Name
------- --- -- ----
269 0.050072 3956 alg
58 0.1301872 740 ati2evxx
61 0.1101584 1708 ati2evxx
50 0.1402016 868 BTTray
38 0.0100144 1888 btwdins
Defining Object Formatting
Windows PowerShell uses XML-based files to define how the hosting application displays an object. The Windows PowerShell *Format.ps1xml files contain declarations that define the formatting for objects. If you have defined new .NET objects, extended existing objects, or you only want to change how Windows PowerShell displays existing objects, you should provide custom format files to enable proper object formatting. This section tells how to provide formatting for objects.
Note
You must never change the default *Format.ps1xml files shipped with Windows PowerShell. Doing so can interfere with the correct operation of the product.
Prepare a Formatting File
The first thing you need to do in formatting your objects is to create a formatting file.
Create a YourProductName.Format.ps1xml file in the same directory as your types file.
Open the file and create the root Configuration node, using the <Configuration></Configuration>delimiters.
Create a ViewDefinitions node using the using the <ViewDefinitions></ViewDefinitions>delimiters.
Customize the ViewDefinitions node as required, adding a View node for each object.
The following topics provide details of customization of the file for view basics and details of specific views.
View Basics
The View node defines how an object is displayed by the hosting application (the default hosting application is powershell.exe).
In the Name node, specify a name for the view, using the <Name></Name> delimiters.
In the ViewSelectedBy node, reference the list of .NET objects to which the view applies.
In the GroupBy node, specify how you want Windows PowerShell to group the objects. For example, a directory listing is grouped by its parent. Each grouping needs a header, as defined by a control node, such as a TableControl node. The header is most relevant when the user performs a recursive directory listing.
Defining Specific Views
Now you can define specific View nodes as required. Each view is defined in its own View node.
Define the header format of the view with a sequence of TableColumnHeader nodes within a TableControl node. Each header has a label, a width, and an alignment.
<TableControl> <TableHeaders> <TableColumnHeader> <Label>DataName</Label> <Width>5</Width> <Alignment>right</Alignment> </TableColumnHeader> <TableColumnHeader> <Label>DataName</Label> <Width>7</Width> <Alignment>right</Alignment> </TableColumnHeader> </TableHeaders> </TableControl>
Add the row format to the TableControl Node. The row format is defined by a sequence of TableRowEntry nodes in the TableRowEntries node. Row entries refer either to a direct property of the underlying object, or to a ScriptBlock node. The ScriptBlock node references the current pipeline object using the "$_" automatic variable.
<TableRowEntries> <TableRowEntry> <TableColumnItems> <TableColumnItem> <PropertyName>OpjectPropertyName</PropertyName> </TableColumnItem> <TableColumnItem> <PropertyName>OpjectPropertyName</PropertyName> </TableColumnItem> <TableColumnItem> </TableRowEntry> </TableRowEntries>
Sample Formatting File
The following XML is a sample formatting file that defines the current display of the Process objects reflected in the sample types file.
<View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Label>Handles</Label>
<Width>7</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>NPM(K)</Label>
<Width>7</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>PM(K)</Label>
<Width>8</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>WS(K)</Label>
<Width>10</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>VS(M)</Label>
<Width>5</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>CPU(s)</Label>
<Width>8</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Width>6</Width>
<Alignment>right</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>HandleCount</PropertyName>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>[int]($_.NonpagedSystemMemorySize /
1024)</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>[int]($_.PagedMemorySize /
1024)</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>[int]($_.WorkingSet / 1024)</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>[int]($_.VirtualMemorySize /
1048576)</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<ScriptBlock>
if ($_.CPU -ne $())
{$_.CPU.ToString("N")}
</ScriptBlock>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Id</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>ProcessName</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
Load the New Formatting
When Windows PowerShell loads its formatting data, the first file to define a view is loaded first. To allow your new object formatting to load, enter the following on the command line.
$formatFile = "$(parse-path $profile)\YourProductName.Format.ps1xml"
update-FormatData -prependpath $formatFile
Test the New Formatting
To verify your object formatting, try several command line entries as a test. Here is an example testing our sample format file.
PS> get-process | select-object -first 5
Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
271 6 1244 3700 33 0.05 2212 alg
58 2 420 1904 18 0.17 744 ati2evxx
69 2 476 2072 19 0.78 3152 ati2evxx
50 3 2208 4256 42 0.09 440 BTTray
38 2 420 1600 17 0.02 1744 btwdins
See Also
Concepts
Windows PowerShell Programmer's Guide