Using MSMQ with a Hosts File entry - msmq

I'm trying to use an alias in the hosts file to point to a server containing an MSMQ. If I specify the actual server name in the MSMQ path then everything works fine:
var queue = new MessageQueue("FormatName:DIRECT=OS:queue-server\Private$\some-queue");
var enumerator = queue.GetMessageEnumerator2();
while (enumerator.MoveToNextRecord())
{
// Do something
}
However if I create the following hosts file entry:
XXX.XXX.XXX.XXX queue-server-alias #queue-server
Then reference the queue using the alias:
var queue = new MessageQueue("FormatName:DIRECT=OS:queue-server-alias\Private$\some-queue");
Then I get the following error:
The queue does not exist or you do not have sufficient permissions to perform the operation.
The hosts file entry is correct and I can ping the alias and it returns the correct IP address. I've read through the following article detailing the various MSMQ path formats but none of them seem to resolve the issue:
Difference between Path name and Format name when accessing MSMQ queues.
Any ideas?

Open your registry, make sure
HKEY_LOCAL_MACHINE\Software\Microsoft\MSMQ\Parameters\IgnoreOSNameValidation
is set to 1 (DWORD value)
This will mean that msmq will not validate the destination queue before trying to send the message.
(from John Breakwell's post here)

Related

Can't Create Receive Connector

So I'm trying to copy a single receive connector from one server to another. I store the receive connector in a variable like so:
$NKCRC = Get-ReceiveConnector "<Source Resource Connector>" | Select *
Then I try to create the new one with the command below:
New-ReceiveConnector -Server $targetServer -Bindings $NKCRC.Bindings -RemoteIPRanges $NKCRC.RemoteIPRanges -Name $NKCRC.Name -TransportRole FrontEndTransport
The source RC is an Exchange 2010 RC and I'm creating it on an Exchange 2016 server. When I run the command, I get the following error:
The values that you specified for the Bindings and RemoteIPRanges parameters
conflict with the settings on Receive connector "<Identity of receive connector on the
target server>" SMTP Relay". A Receive connector must have a unique combination of a local
IP address & port bindings and remote IP address ranges. Change at least one of these
values.
I checked the mentioned RC and found they don't have the exact same settings for ANYTHING AT ALL, Bindings or RemoteIPRanges. I'm kinda at a loss. The bindings and RemoteIPRanges for each RC is below:
Source RC Bindings: {0.0.0.0:25}
Count of Source RC RemoteIPRanges: 60 (Rather than post them all, lol)
RC that the Exchange thinks is a duplicate
Bindings: {0.0.0.0:25, 10.200.154.79:25}
Count of Source RC RemoteIPRanges: 50
So obviously they aren't duplicates, right? What am I missing?

MessageQueue.Exists(QueueName) returns false but it exists

The problem I'm having is with this code:
if (!MessageQueue.Exists(QueueName))
{
MessageQueue.Create(QueueName, true);
}
It will check if a queue exists; if it doesn't I want it to create the queue. This code has been working and hasn't changed for a few months. Today I started receiving this error:
[MessageQueueException (0x80004005): A queue with the same path name
already exists.] System.Messaging.MessageQueue.Create(String path,
Boolean transactional) +239478
The queues are local and if I delete the specific queue it will work once. After the queue is created it starts to fail again with the same error message.
It looks like the issue may be because of the Network Load Balancing (NLB) configuration. I was unaware of a change that recently put the machine in a NLB environment. The configuration we are using is an unsupported one.
More information is in How Message Queuing can function over Network Load Balancing (NLB).

Cannot read remote private queue

I'm trying to get MSMQ 5 working on my two Windows Server 2008 R2 virtual machines.
I can send to local and remote private queues, and I can read from local private queues.
I can't read from remote private queues.
I've read a number of suggestions, especially the ones summarised by John Breakwell at MSMQ Issue reading remote private queues (again).
Things I've already done:
Turned off firewalls on both machines.
Ensured that Everyone and AnonymousLogon have full control of the queues. (If I take away AnonymousLogon access, then I can't remotely send to the queue, and the message ends up with "Access is denied" on the receiving machine.)
Allowed Nonauthenticated Rpc on both machines.
Allowed NewRemoteReadServerAllowNoneSecurityClient on both machines.
the sending code fragment is:
MessageQueue queue = new MessageQueue(queueName, false, false, QueueAccessMode.Send);
Message msg = new Message("Blah");
msg.UseDeadLetterQueue = true;
msg.UseJournalQueue = true;
queue.Send(msg, MessageQueueTransactionType.Automatic);
queue.Close();
The receiving code fragment is:
queueName = String.Format("FormatName:DIRECT=OS:{0}\\private$\\{1}",host,id);
queue = new MessageQueue(queueName, QueueAccessMode.Receive);
queue.ReceiveCompleted += new ReceiveCompletedEventHandler(receive);
queue.BeginReceive();
...
public void receive(object sender, ReceiveCompletedEventArgs e)
{
queue.EndReceive(e.AsyncResult);
Console.WriteLine("Message received");
queue.BeginReceive();
}
My queueName ends up as FormatName:DIRECT=OS:server2\private$\TestQueue
When I call beginReceive() on the queue, I get
Exception: System.Messaging.MessageQueueException (0x80004005)
at System.Messaging.MessageQueue.MQCacheableInfo.get_ReadHandle()
at System.Messaging.MessageQueue.ReceiveAsync(TimeSpan timeout, CursorHandle cursorHandle, Int32 action, AsyncCallback callback, Object stateObject)
at System.Messaging.MessageQueue.BeginReceive()
I've used Wireshark on Server1 to look at the network traffic. Without posting all the detail, it seems to go through the following stages. (Server1 is trying to read from a queue on Server2.)
Server1 contacts Server2, and there is an NTLMSSP challenge/response negotiation. A couple of the responses mention "Unknown result (3), reason: Local limit exceeded".
Server1 sends Server2 an rpc__mgmt_inq_princ_name request, and Server2 replies with a corresponding response.
There's some ldap exchanges looking up the domain, then a referral to ldap://domain/cn=msmq,CN=Server2,CN=Computers,DC=domain which returns a "no such object" response.
Then there's some SASL GSS-API encrypted exchange with the LDAP server
Then connections to the ldap server and Server2 are closed.
I've tried enabling Event Viewer > Applications and Services Logs > Microsoft > Windows > MSMQ > End2End. It shows messages being sent, but no indication of why trying to receive is failing.
How can I debug this further?
The problem was related to domains. Server1 and Server2 were part of a development domain. My login account was part of the corporate domain. The development domain trusts the corporate domain enough for me to log in, be a member of administrators, install features etc. But it seems to be insufficient trust to read remote queues.
I found this by looking into public queues. If I was having trouble reading remote private queues, perhaps I should get more data by trying public queues. After installing the appropriate directory integration feature, I was able to create a public queue, but not see it in the list of public queues. Trying to refresh the list of public queues gave me this error:
Not all
public queues can be displayed. Only public queues cached locally can be
displayed. Error: The object was not found in Active Directory.
Google pointed me to John Breakwell's answer to a similar problem here, which indicates that trust relationships don't work across messaging protocols.
Try to use the standard Receive method instead and specify the transaction type as it seems like BeginReceive does not support receiving from transactional queues.
Message msg = queue.Receive(MessageQueueTransactionType.Automatic);
MSMQ does not always return logical error messages...
System.Messaging.MessageQueueException (0x80004005)
at System.Messaging.MessageQueue.MQCacheableInfo.get_ReadHandle()
This error can also be caused due to the BeginReceive Read on an non-existent queue. Check the configuration to ensure queue path specified exists physically and has "Everyone" full permissions

Can I open a clustered MQ queue for writing in Perl?

If I have a Websphere MQ queue defined on another queue manager in the cluster, is there a way I can open it for writing using the Perl interface? The code below brings back mqrc 2085.
$messageQ = MQSeries::Queue->new
(
QueueManager => $qMgr,
Queue => $queue,
Options => $openOpt
) or die ">>>ERROR2: Unable to open the queue: $queue\n";
}
Yes! The Perl modules are a thin veneer over the WMQ API and expose all the basic options and most of the really esoteric stuff as well.
When you open a queue, WebSphere MQ performs name resolution on the values you provide for Queue and QMgr names. If you provide both a Queue and a QMgr name then the object reference is fully qualified and WMQ will attempt to open it as named. So if the name you provide is the local QMgr and the clustered queue does not have a locally defined instance, the open will fail with a 2085 Unknown Object Name.
The trick to opening a clustered queue is to provide a null value for the QMgr name. This causes name resolution to check the local QMgr for a queue of the same name, then finding none it checks the cluster repository and resolve the open to the clustered queue. Note that the queue must be advertised to the cluster for this to work. Specifically, the CLUSTER or CLUSNL attribute of the target queue must be non-blank and refer to a cluster that the source QMgr participates in. Similarly, the destination QMgr must also participate in the same cluster as the source QMgr.
Note also that if you specify a QMgr name on the open that is not the local QMgr, then WMQ will attempt to resolve the QMgr name only. If it can resolve a route to that QMgr then it will send the message there. This means that in a cluster you can send a message to any queue on any QMgr so long as you know the fully-qualified name.
Finally, you can define a local alias over a clustered queue. For example if you are on QMGRA and DEF QA(TARGET.QUEUE) TARGQ(TARGET.QUEUE) and then on QMGRB and QMGRC in the same cluster you DEF QL(TARGET.QUEUE) CLUSTER(MYCLUS) then it is possible to open QMGR=QMGRA QUEUE=TARGET.QUEUE and still have it work as expected. Note that the alias is NOT advertised to the cluster but the target queue is. The only issue with this approach is that the first time it is opened the API call may fail if the cluster query takes too long. When I do this in Production, I always use amqsput on the alias ahead of time to make the QMgr query the repository before the actual application opens the queue. Why would you do this? If security is a concern you probably don't want to authorize all apps directly to the cluster XMitQ because, as noted above, they could then put a message onto any queue on any QMgr in the cluster, including SYSTEM.ADMIN.COMMAND.QUEUE. The alias gives you a place to hang authorizations and restrict the user to specific destinations in the cluster.
So short answer, make sure you provide a null QMgr name on the Open call or set up a local alias over the clustered queue. For more about the security aspects of this, see the WMQ Security presentation at http://t-rob.net/links

What is the format of remote queues' address

Our MQ service will be moved to outside of local server. I can see current destination queue address as ".\Private$\eventQueue".
What is the format of remote address for sending messages?
From Technet:
Private queues are accessible only by Message Queuing applications
that know the full path name, the direct format name, or
the private format name of the queue, as follows:
* Path name:ComputerName\private$\QueueName.
* Path name on local computer: \private$\QueueName.
* Direct format name:: DIRECT=ComputerAddress\PRIVATE$\PrivateQueueName.
* Private format name: PRIVATE=ComputerGUID\QueueNumber.
See this article for more on queue names. One thing to watch out for is that it's not possible to tell if a remote private queue is transactional or not, and if you post with the wrong transactional option set the message is discarded.
You can't access private queues remotely (that's why they're private). You can use the following queue name to access public queues, however:
FormatName:DIRECT=OS:<machine>\<queue>
(This works with the .NET library, I'm not sure about the native library)