Sometimes it can be useful to retrieve the number of messages in an MSMQ queue, for example for monitoring. However, it’s not immediately apparent how to do it if you google it, so here are my thoughts on the subject.
Other blog posts suggest iterating over messages (e.g. Counting Messages in an MSMQ MessageQueue from C#) or doing it using WMI. WMI is the best alternative in my opinion and if you want a quick way of doing it then PowerShell is the easiest:
$queues = Get-WmiObject Win32_PerfFormattedData_msmq_MSMQQueue $queues | ft -property Name,MessagesInQueue
The result will be something similar to this:
Name MessagesInQueue ---- --------------- active714\private$\notify_queue$ 0 active714\private$\deltagarloggservice\deltagarloggservi... 0 active714\private$\order_queue$ 0 active714\private$\admin_queue$ 0 Computer Queues 27
This can also be done on remote machines:
$host = ... $cred = get-credential $queues = Get-WmiObject Win32_PerfFormattedData_msmq_MSMQQueue -computer $host -credential $cred $queues | ft -property Name,MessagesInQueue
The Get-Credential Cmdlet will display a login dialog which is fine in interactive sessions but if you need to set the credentials in a non-interactive script, then the tip in this blog post might help: PowerShell – How to create a PSCredential object.
Retrieving message counts from code takes a little more coding but here’s an example in C# that searches for a given queue and returns its message count:
private static int GetMsmqMessageCount(string queuePath, string machine, string username, string password) { var options = new ConnectionOptions {Username = username, Password = password}; var path = string.Format(@"\\{0}\root\CIMv2", machine); var scope = new ManagementScope(path, options); scope.Connect(); string queryString = String.Format("SELECT * FROM Win32_PerfFormattedData_msmq_MSMQQueue WHERE Name = '{0}'", queuePath); var query = new ObjectQuery(queryString); var searcher = new ManagementObjectSearcher(scope, query); IEnumerable<int> messageCountEnumerable = from ManagementObject queue in searcher.Get() select (int) (UInt64) queue.GetPropertyValue("MessagesInQueue"); return messageCountEnumerable.First(); }
This code also uses WMI but this time we do a query rather than enumerate all queues.
The above snippets has worked well for us so I felt it would be useful to post them here. Please leave a comment if you have issues with them or suggestions for improvement!
/Emil
Update:
If some queues are not showing up then perhaps they’re not active. Make sure that you have an active listener or have sent messages to the queues. It might also help restarting the “Message Queueing” service.
See here: http://serverfault.com/questions/269491/wmi-missing-msmq-queue-name
/Emil
Unfortunately when using this method, the queue names get truncated to 64 characters which for most people like myself, can make this option unusable. When querying for queues on a remote machine, the queue name comes back looking like this: MachineName\private$\QueueName so with that extra text prepended to the beginning of the queue name, you can easily exceed 64 characters. If only Microsoft would just implement a MessageCount property… See: http://connect.microsoft.com/VisualStudio/feedback/details/91525/system-daignostics-performancecounter-fails-when-using-instance-name-64-characters
Thank you for sharing part of your knowledge base!
This is quite useful and makes my job all the more easy due to restricted access for MSMQ queues via computer management to remote machines; powershell is completely unrestricted in this regard.
How can I purgue queue in remote server from a client machine?
My user in client machine has FULL CONTROL in queue in remote server.
Hi @kiquenet . It’s been some time since I worked with MSMQ, but this looks similar to what you describe: http://stackoverflow.com/questions/11793441/purge-msmq-queue-and-reset-iis-from-a-bat-file
/Emil
I did same but it says invalid query.
@wishesh, from that brief description it’s very hard to know what might be wrong. I haven’t worked with MSMQ for years now but I’d suggest checking that you haven’t mispelled a queue name or such. You could also check for errors in the event logs.
this is how I passing it.
var q = MessageQueue.GetPrivateQueuesByMachine(machineName)
.Where(
x =>
x.QueueName.Contains(“testqueue”) ||
x.QueueName.Contains(“restqueue”));
var mQuery = from x in q select new {
qName = x.QueueName,
msgCount = GetMessageCount(string.Format(“.\\{0}”, x.QueueName), machineName, “”, “”)
};
I think I am getting this Management exception (in valid query) due to where clause. If do not put it, it works fine. but I can’t get count on each queues.
Hard to say. I would try googling with the exact error message and hope that someone at StackOverflow has a solution 🙂
Hi.. Thank you for sharing this.. it helped a lot !!
I’ve found the solution with the error of ‘invalid query’ by adding [where name = ‘{0}’]. It turns out that the queuePath rather than using “active714\\private$\\admin_queue”, instead we should send “active714\\\\private$\\\\admin_queue”.
*note that backslash escaped twice