Displaying constant names (rather than values) in PowerShell cmdlets

I’ve mentioned before that I’m working on some PowerShell cmdlets for WebSphere MQ. I thought I’d pass on a few tips that I picked up this week on improving the usability of the information displayed by Get- cmdlets in PowerShell.

The easiest way to explain it is to demonstrate with an example:

Before

Consider one of my cmdlets before:

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE

InhibitGet                : 1
ProcessName               :
MaximumDepth              : 5000
MaximumMessageLength      : 4194304
BackoutThreshold          : 0
BackoutRequeueName        :
Shareability              : 1
DefaultInputOpenOption    : 2
HardenGetBackout          : 1
MessageDeliverySequence   : 0
RetentionInterval         : 999999999
DefinitionType            : 1
Usage                     : 0
OpenInputCount            : 0
OpenOutputCount           : 0
CurrentDepth              : 0
CreationDateTime          : 10/11/2007 15:17:38
InitiationQueueName       :
TriggerControl            : 0
TriggerType               : 1
TriggerMessagePriority    : 0
TriggerDepth              : 1
TriggerData               :
Scope                     : 1
DepthHighEvent            : 0
DepthHighLimit            : 80
DepthLowEvent             : 0
DepthLowLimit             : 20
DepthMaximumEvent         : 1
ServiceInterval           : 999999999
ServiceIntervalEvent      : 0
ClusterName               :
ClusterNamelist           :
DefaultBind               : 0
ClusterWorkLoadRank       : 0
ClusterWorkLoadPriority   : 0
ClusterWorkLoadUseQ       : -3
TPIPE                     :
QueueAccounting           : -3
QueueMonitoring           : -3
QueueStatistics           : -3
NonPersistentMessageClass : 0
PagesetId                 : 0
QueueManager              : IBM.WMQ.MQQueueManager
Name                      : SYSTEM.DEFAULT.LOCAL.QUEUE
QueueType                 : 1
Description               :
InhibitPut                : 0
DefaultMessagePriority    : 0
DefaultMessagePersistence : 0
AlterationDateTime        : 21/11/2007 11:46:23

After

Now take a look at what it looks like:

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE

InhibitGet                : Inhibited
ProcessName               :
MaximumDepth              : 5000
MaximumMessageLength      : 4194304
BackoutThreshold          : 0
BackoutRequeueName        :
Shareability              : Shareable
DefaultInputOpenOption    : Shared
HardenGetBackout          : Hardened
MessageDeliverySequence   : 0
RetentionInterval         : 999999999
DefinitionType            : Predefined
Usage                     : Normal
OpenInputCount            : 0
OpenOutputCount           : 0
CurrentDepth              : 0
CreationDateTime          : 10/11/2007 15:17:38
InitiationQueueName       :
TriggerControl            : Off
TriggerType               : First
TriggerMessagePriority    : 0
TriggerDepth              : 1
TriggerData               :
Scope                     : Qmgr
DepthHighEvent            : 0
DepthHighLimit            : 80
DepthLowEvent             : 0
DepthLowLimit             : 20
DepthMaximumEvent         : 1
ServiceInterval           : 999999999
ServiceIntervalEvent      : None
ClusterName               :
ClusterNamelist           :
DefaultBind               : OnOpen
ClusterWorkLoadRank       : 0
ClusterWorkLoadPriority   : 0
ClusterWorkLoadUseQ       : UseAsQmgr
TPIPE                     :
QueueAccounting           : Qmgr
QueueMonitoring           : Qmgr
QueueStatistics           : Qmgr
NonPersistentMessageClass : Normal
PagesetId                 : 0
QueueManager              : IBM.WMQ.MQQueueManager
Name                      : SYSTEM.DEFAULT.LOCAL.QUEUE
QueueType                 : Local
Description               :
InhibitPut                : Allowed
DefaultMessagePriority    : 0
DefaultMessagePersistence : NotPersistent
AlterationDateTime        : 21/11/2007 11:46:23

What do you think? More readable, right?

What is going on?

The Get-WMQQueue cmdlet writes ‘WebSphere MQ queue’ objects to the pipeline. The queue’s properties were stored as int’s, strings, and DateTime objects. Some of the ints were used to store a choice between constants.

For example, QueueType contained a value chosen from:

    public const int MQQT_ALL = 1001;
    public const int MQQT_LOCAL = 1;
    public const int MQQT_MODEL = 2;
    public const int MQQT_ALIAS = 3;
    public const int MQQT_REMOTE = 6;
    public const int MQQT_CLUSTER = 7;

These are the integers being displayed in the Get- cmdlet shown above.

It was the same in the Set- cmdlets when you want to make a change:

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Set-WMQQueue -InhibitPut 1 
PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Select Name, InhibitPut 

Name                                                InhibitPut 
----                                                ---------- 
SYSTEM.DEFAULT.LOCAL.QUEUE                                   1 

You could always use the constant names in commands…

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Set-WMQQueue -InhibitPut ([IBM.WMQ.MQC]::MQQA_PUT_INHIBITED) 
PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Select Name, InhibitPut 

Name                                                InhibitPut 
----                                                ---------- 
SYSTEM.DEFAULT.LOCAL.QUEUE                                   1 

but it still outputs the int in Get- commands, and the constants would be a pain to memorise for commands.

Improving – using enums

Instead of storing QueueType as an int, and store a collection of constant ints for the possible values, I can use an enum.

    public enum QueueTypes
    {
        All = 1001,
        Local = 1,
        Model = 2,
        Alias = 3,
        Remote = 6,
        Cluster = 7
    };

When you do this, by default PowerShell will display the enum value name rather than underlying value – producing the more readable Get-WMQQueue output you can see above.

Self-documenting commands… using enums

Unlike using ints, the use of enums also makes it much easier for users to find out what the valid values are for each property.

For example, if you can see that InhibitGet is set to ‘Allowed’, how do you know what is the right value for ‘not allowed’?

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Get-Member InhibitGet 

   TypeName: WebSphereMQ.MQLocalQueue 

Name       MemberType Definition 
----       ---------- ---------- 
InhibitGet Property   WebSphereMQ.MQC+InhibitGetTypes InhibitGet {get;set;}

The ‘+’ symbol in the type definition tells you that the type is an enum called InhibitGetTypes in the WebSphereMQ.MQC class.

And to find out the valid values:

PS C:\> Get-EnumValues([WebSphereMQ.MQC+InhibitGetTypes]) 

     Name Value 
     ---- ----- 
  Allowed     0 
Inhibited     1 

To use this, you can just use the enum value – without having to identify the full class name:

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE * | Set-WMQQueue -InhibitGet Inhibited 
PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE * | Select Name, InhibitGet 

Name                                                InhibitGet 
----                                                ---------- 
SYSTEM.DEFAULT.LOCAL.QUEUE                           Inhibited 

Alternatively, you could always be lazy and make an intentional error – using the error message feedback to guide you…

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE * | Set-WMQQueue -InhibitGet THIS_DEFINITELY_SHOULDNT_WORK 
Set-WMQQueue : Cannot bind parameter 'InhibitGet'.  
Cannot convert value "THIS_DEFINITELY_SHOULDNT_WORK" to type "WebSphereMQ.MQC+InhibitGetTypes" due to invalid enumeration values.  
Specify one of the following enumeration values and try again.  
The possible enumeration values are "Allowed, Inhibited". 

That said, by using the same int values in the enum, it means the full constants would still work for those users familiar with them:

PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Set-WMQQueue -InhibitGet ([IBM.WMQ.MQC]::MQQA_GET_INHIBITED) 
PS C:\> Get-WMQQueue SYSTEM.DEFAULT.LOCAL.QUEUE DALE | Select Name, InhibitGet 

Name                                                InhibitGet 
----                                                ---------- 
SYSTEM.DEFAULT.LOCAL.QUEUE                           Inhibited 

PowerShell handles enums really well – and it all helps improve the usability of your sysadmin cmdlets if you use them properly.

Thanks to Don Jones for helping to point me in the right direction, and $cript Fanatic for the Get-EnumValues function.

Tags: , , ,

Comments are closed.