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.

noteNote:
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

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.

Important 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.

  1. Create a YourProductName.Types.ps1xml text file in the same directory as the default types file.

  2. Open the file and create the root Types node, using the <Types></Types> delimiters.

  3. 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.

Important 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.

  1. Create a YourProductName.Format.ps1xml file in the same directory as your types file.

  2. Open the file and create the root Configuration node, using the <Configuration></Configuration>delimiters.

  3. Create a ViewDefinitions node using the using the <ViewDefinitions></ViewDefinitions>delimiters.

  4. 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).

  1. In the Name node, specify a name for the view, using the <Name></Name> delimiters.

  2. In the ViewSelectedBy node, reference the list of .NET objects to which the view applies.

  3. 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.

  1. 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>  
    
  2. 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

Community Additions

Show: