Search code examples
c#powershellpropertiespowershell-cmdlet

PowerShell Output Formatting from C# using DefaultDisplayPropertySet


I am writing a PowerShell cmdlet in C#. I know one may use a formatting file to specify default output properties of a cmdlet (Writing a Windows PowerShell Formatting File) but I recently came across a more streamlined technique (i.e. just a couple lines of code; no separate formatting file needed) to do this in a scripted cmdlet (with thanks to Kirk Munro's Define default properties for custom objects, where I copied this code sample from):

$myObject = New-Object PSObject
$myObject | Add-Member NoteProperty Name ‘My Object’
$myObject | Add-Member NoteProperty Property1 1
$myObject | Add-Member NoteProperty Property2 2
$myObject | Add-Member NoteProperty Property3 3
$myObject | Add-Member NoteProperty Property4 4
$myObject | Add-Member NoteProperty Property5 5

$defaultProperties = @('Name','Property2','Property4')
$defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$defaultProperties)
$PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
$myObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers
$myObject

The last line above displays the object, showing just the specified default properties. I have been searching for an equivalent way to do the same steps in my C# cmdlet but to no avail: I see no obvious access to PSStandardMembers on the PSCmdlet base class nor do I find any posts discussing the matter. Is this possible and, if so, how?


2015.03.26 Update With thanks to @Jaykul for pointing the way, for completeness I am attaching the actual C# code to do the task. I wrote this method to be reusable so along with the object you wish to "filter" you also pass in the property names of interest.

PSObject SetDefaultProperties(object obj, IEnumerable<string> defaultProperties)
{
    var psObject = new PSObject(obj);
    psObject.Members.Add(
        new PSMemberSet("PSStandardMembers", new PSMemberInfo[]
        {
            new PSPropertySet("DefaultDisplayPropertySet", defaultProperties)
        }));
    return psObject;
}

Here is how one might use it in a cmdlet--instead of sending the full result object to WriteObject, funnel it through the new method.

string[] DefaultProperties = {"Name", "Property2", "Property4" };
base.WriteObject(SetDefaultProperties(myObject, DefaultProperties));

Solution

  • You have to wrap the object in a PSObject, and then use the methods of that wrapper to set those properties.

    using System.Management.Automation;
    public class Whatever {
       public string One { get { return "This is one"; } }
       public string Two { get { return "This is two"; } }
       public string Three { get { return "This is three"; } }
       public string Four { get { return "This is four"; } }
    
       public static PSObject Get() {
    
          var w = new Whatever();
          var pso = new PSObject(w);
          var display = new PSPropertySet("DefaultDisplayPropertySet",new []{"One","Two"});
          var mi = new PSMemberSet("PSStandardMembers", new[]{display});
          pso.Members.Add(mi);
    
          return pso;
       }
    }
    

    To be very clear and explicit: I am answering your question, but I do not recommend this approach! I don't like this even in PowerShell scripts, although it's sometimes expedient, but I emphatically advise against doing this in compiled code.

    By doing this you may be breaking some of the expectations of the ETS system. This is not a "more streamlined technique" -- it's an end-run around the system, and I believe it will override any PSTypes file the end user might create, thus subtly breaking their ability to control formatting (which is a core feature of PowerShell).

    When you're creating a simple PowerShell script, that's probably excusable (since it's easy enough for someone to tweak), but when you're distributing a compiled module, you should just make the PSTypes XML file and take care of formatting the correct, extensible way so that it is modifiable by your users and their sysadmins.