ETS CodeMethods in PowerShell

Marco Shaw recently asked on the powershell newsgroup:

Anyone have a working example of using "CodeMethod" to define methods
for a custom object?

And funnily enough, not even Microsoft themselves seem to have a decent working example. So, spelunking in the packaged Types.ps1xml that comes with a PowerShell install I found only three examples. Let's look at the ETS definition for one of them (XmlNode.ToString) in Types.ps1xml:

<Type>
  <
Name>System.Xml.XmlNode</Name>
    <
Members>
      <
CodeMethod>
        <
Name>ToString</Name>
        <
CodeReference>
          <
TypeName>Microsoft.PowerShell.ToStringCodeMethods</TypeName>
          <
MethodName>XmlNode</MethodName>
        </
CodeReference>
      </
CodeMethod>
   </
Members>
</
Type>

Using Reflector, I took a look at the managed code providing this service - btw, ETS CodeMethods are always provisioned by static methods on a managed type:

public static class ToStringCodeMethods
{
    ...
    public static string XmlNode(PSObject instance);
    ...
}


The C# 3.0 users among you will see a remarkable similarity to Extension Methods here, except here ETS CodeMethods can also replace a native method if you so desire. To define a new CodeMethod, you need to provide the full type name, the name of the static method and the ETS method name for the extension method on the target type. In this particular example, all instances of XmlNode exposed in PowerShell will now have their native ToString method replaced with this new one. When you invoke ToString on the XmlNode instance, the static method ToStringCodeMethods.XmlNode will be invoked and the instance parameter will be passed the PSObject wrapped XmlNode. Taking the only three examples in Types.ps1xml at face value, one might assume that CodeMethods can only be parameterless, but it appears not to be the case...

ETS Code Methods with additional parameters

A little experimentation verified that to me that we're not stuck with parameterless codemethods; any additional parameters you define on your static method will be bound to parameters provided in a script invocation of the ETS CodeMethod. The first argument is mandatory for any statics providing CodeMethod services: it will always be passed the ETS extended instance. Here are three examples of some multi-argument signatures and the backing managed code to provide ETS with the implementation:

<Types>
 <
Type>
  <
Name>System.String</Name>
  <
Members>
  <
CodeMethod>
   <
Name>Test1</Name>
   <
CodeReference>
    <
TypeName>Nivot.CodeMethods.TestCodeMethods</TypeName>
    <
MethodName>TestNoArguments</MethodName>
   </
CodeReference>
  </
CodeMethod>
  <
CodeMethod>
   <
Name>Test2</Name>
   <
CodeReference>
    <
TypeName>Nivot.CodeMethods.TestCodeMethods</TypeName>
    <
MethodName>TestOneArgument</MethodName>
   </
CodeReference>
  </
CodeMethod>
  <
CodeMethod>
   <
Name>Test3</Name>
   <
CodeReference>
    <
TypeName>Nivot.CodeMethods.TestCodeMethods</TypeName>
    <
MethodName>TestVariableArguments</MethodName>
   </
CodeReference>
  </
CodeMethod>
 </
Members>
 </
Type>
</
Types>

And here is the corresponding backing managed code signatures:

public static class TestCodeMethods
{
    // Methods
    public static string TestNoArguments(PSObject instance) { ... }
    public static string TestOneArgument(PSObject instance, PSObject arg1) { ... }
    public static string TestVariableArguments(PSObject instance, params PSObject[] args) { ... }
}
Have fun!

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List