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: c#, enum, powershell, webspheremq