Automatic properties in PowerShell… and how you can almost have them for your custom types

For certain types, PowerShell has automatic properties, by this I mean PowerShell is able to inspect the object and then expose properties where normally you would need to use a string indexer.

Like so:

$xbooks = [xml]"<Books><Book><Title>PowerShell in Action</Title></Book></Books>" 
$xbooks.Books.Book.Title

Similar functionality is available for COM, WMI, ADO.Net, and AD types. It’s one of the core features of PowerShell, and its simplicity and elegance makes even diehard UNIX types sit up and take notice.

But if you’re writing your own cmdlet, navigation provider, or are hosting PowerShell, and you wish to provide an adapter for your own type – you will quickly find that adapters and rest of the infrastructure for automatic properties are internal classes and unavailable to you.

The best option you have is something along the following:

public PSObject CreateCustomPSObject(MyType mytype )
{
    PSObject pso = new PSObject(mytype);
    foreach (string name in MyColumnNames)     
    { 
        string getter = String.Format("$this[\"{0}\"]", name); 
        string setter = String.Format("$this[\"{0}\"] = $value", name); 
        pso.Properties.Add(new PSScriptProperty(name,                                        InvokeCommand.NewScriptBlock(getter),                                InvokeCommand.NewScriptBlock(setter))); 
    
    } 
    return pso; 
}
WriteItemObject(CreateCustomPSObject(mytype));

This will work, but the output from get-member won’t be as clean as it is for a DataRow or other adapted types. Even worse, this option isn’t available at all for hosted scenarios as there no instance of CommandInvocationIntrinsics available from a Runspace or Pipleline.

No Comments