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