Recipe 7.13. Inspecting the Contents of a QueueProblemYou need to enumerate the contents of a queue, or examine a specific message in a queue. SolutionUsing a graphical user interface
Using VBScript' This code enumerates the messages within a given queue. ' ------ SCRIPT CONFIGURATION ------ ' The host name of the Exchange server strHostname = "<ExchangeServerName>" ' e.g., red-exch02 ' Name of the SMTP queue to search for messages strQueueName = "<SMTPQueueName>" ' e.g., 3sharp.com ' ------ END CONFIGURATION --------- ' Get the Exchange Namespace WMI object Set objWMIExch = GetObject("winmgmts://" & strHostname &_ "/root/MicrosoftExchangeV2") ' Get the list of queues and process our desired queue Set objQueuesList = objWMIExch.InstancesOf("Exchange_SMTPQueue") For Each objQueueInst in objQueuesList ' Make sure this queue is the one we're looking for; if not, skip it If objQueueInst.QueueName = strQueueName Then strMsgInfo = strMsgInfo & "Queue: " & objQueueInst.QueueName & " (" &_ objQueueInst.QueueID & ")" & VbCrLF Set objMsgsList = objWMIExch.ExecQuery ("Select * From " &_ "Exchange_QueuedSMTPMessage Where ProtocolName='SMTP' And LinkId='" &_ objQueueInst.LinkID & "' And LinkName='" &_ objQueueInst.LinkName & "' And QueueId='" &_ objQueueInst.QueueID & "' And QueueName='" &_ objQueueInst.QueueName &"' And VirtualMachine='" &_ objQueueInst.VirtualMachine & "' And VirtualServerName='" &_ objQueueInst.VirtualServerName & "'") For each objMsgInst in objMsgsList strMsgInfo = strMsgInfo & " Message " & _ objMsgInst.MessageID & VbCrLF & _ " Sender: " & objMsgInst.Sender & VbCrLF &_ " MessageID: " & objMsgInst.MessageId & VbCrLF Next End If Next Wscript.Echo strMsgInfo DiscussionEnumerating the messages in a queue using ESM Queue Viewer is difficult; the Queue Viewer, as mentioned in Recipe 7.12, uses the Queue API to provide a unified view of links and queues. Each link represents the next physical hop for a message, so if your Exchange server is performing its own SMTP deliveries to the Internet, you will have one link for each discrete MX host. Depending on your traffic patterns and who you are sending messages to, you may find that each destination has its own link, giving you the effect of having a separate queue. If your Exchange server is handing mail off to a smarthost, however, you will see a single link for that smarthost in the Queue Viewer display; that link actually contains all of the queues that may exist. You cannot find any information in the Queue Viewer to determine which actual queue a given message is in, even when using the advanced search and filter facilities. In Exchange 2000, you do not have a scripting interface to enumerate messages in queues. Exchange Server 2003 provides several new WMI classes that give you the ability to determine the precise queue that holds a specific message, shown in Table 7-5.
The VBScript solution shows how to use these classes in combination with the classes shown in Recipe 7.12 to enumerate the contents of a script. We start by connecting to the Exchange WMI namespace and retrieving a list of the Exchange_SMTPQueue objects on the server. You need to find a way to filter this list down to the specific queue that you are interested in; in our script, we check the QueueName property against a string we know ahead of time (the destination's domain name). Once we have the right queue, we retrieve the collection of messages in the queue using a WQL query to select against the server, virtual server instance, link, and queue. We then work through those messages using a For Each loop and examine the properties we are interested in. When you create the WQL query string to filter your Exchange_SMTPQueue objects, you should use at a minimum all of the following properties:
Note that the script pulls all of the properties (except for ProtocolName) from the retrieved queue object for inclusion in the WQL query. You can use presupplied strings for most of these properties, but be careful when doing so with the LinkID and QueueID properties. Since queues and links are generated as needed, their IDs are dynamically generated; queue IDs are regenerated whenever Exchange attempts to retry delivery of the messages in that queue. Using static strings can easily cause you to be searching against the wrong information and turning up an empty result set. At the time of this writing, the sample script for the Exchange_QueuedMessage class on the MSDN Exchange WMI reference demonstrates the use of the Count property with a collection of Exchange_QueuedMessage objects. This is an error; this class does not have the Count property available for collections. See AlsoRecipe 7.0, Recipe 7.12 for enumerating queues, and Recipe Recipe 7.14 for deleting messages from queues, MS KB 823489 (How to Use Queue Viewer to Troubleshoot Mail Flow Issues), MSDN: Exchange_QueuedMessage, MSDN: Exchange_QueuedSMTPMessage, and MSDN: Exchange_QueuedX400Message |