How to modify the MachineQuota for MSMQ in Domain Mode through code
Our support website does a pretty good job for telling you how you can modify the MachineQuota setting for MSMQ here. Unfortunately, if you need a way to do this programmatically and your installation happens to be in "Domain Mode", then there really isn't enough information here. Fortunately using the DirectoryEntry object makes this a pretty easy task.
The directory object for MSMQ (called msmq) is contained in Active Directory when in domain mode. That object is located at the LDAP path derived from the algorithm below:
<fqdn>/X/<machine name>/msmq
Where X is evaluated as:
if <machine name> is a domain controller then
x = "Domain Controllers"
else
x = "Computers"
In my case, I had a domain named “PKMSMQ.PKING.COM”. My domain controller was the computer “MSMQ-AD”, and that was the machine I installed MSMQ on. Realize that is not recommended to install MSMQ on the domain controller, but I took a short cut here instead. My complete LDAP object path in this case is:
LDAP://CN=msmq,CN=MSMQ-AD,OU=Domain Controllers,DC=PKMSMQ,DC=PKING,DC=COM
If I had been working on a server within that domain, My LDAP object path would have looked like this:
LDAP://CN=msmq,CN=MSMQSERVER,CN=Computers,DC=PKMSMQ,DC=PKING,DC=COM
Notice the difference here. 'Domain Controllers' is an organizational unit and 'Computers' is just a container. I missed that difference in my original post.
Some simple code to adjust the value is shown below:
// Get the object and the value
DirectoryEntry de = new DirectoryEntry(<YOUR LDAP PATH>);
int value = (int) de.Properties["mSMQQuota"].Value;
// Remove one from the value and set it
value--;
de.Properties["mSMQQuota"].Value = value;
de.CommitChanges();
// Close the directory entry
de.Close();
Hope this helps someone!
<UPDATED - Feb 9. 2012>
Some additional details on this solution were discovered after I published this article. In some cases (Windows 7 machines), mSMQQuota is not set. Instead a default value is used and this code:
int value = (int) de.Properties["mSMQQuota"].Value;
will cause an exception to be thrown. To set the value int this case, you can avoid the exception by not checking the value first and just setting it. The default value is 1048576 KB and setting the value is as easy as:
de.Properties["mSMQQuota"].Value = 1048576;
de.CommitChanges();
A better code sample in this case is shown below:
// Get the object and the value
DirectoryEntry de = new DirectoryEntry(lblObjName.Text);
bool result = false;
try
{
result = de.Properties.Contains("mSMQQuota");
}
catch (Exception ex)
{
// If we throw an exception here, MSMQ may not be installed in AD mode
MessageBox.Show(this, string.Format("{0}{1}{2}",
"The msmq configuration object was not found. ",
"MSMQ may not be installed in AD mode.\r\n\r\n",
ex.Message),
"MSMQ Directory App", MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
de.Close();
return;
}
if (!result)
{
// Property is not set yet
DialogResult dr = MessageBox.Show(this, string.Format("{0}{1}",
"mSMQQuota is not found. Property is not set yet. ",
"Do you wish to set it to the default value of 1048576 KB?"),
"MSMQ Directory App", MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (DialogResult.Yes == dr)
{
de.Properties["mSMQQuota"].Value = 1048576;
de.CommitChanges();
}
}
else
{
int value = (int)de.Properties["mSMQQuota"].Value;
// Remove one from the value and set it
value--;
de.Properties["mSMQQuota"].Value = value;
de.CommitChanges();
MessageBox.Show(this, string.Format(
"mSMQQuota changed to {0} on object: {1}",
value, lblObjName.Text), "MSMQ Directory App",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
// Close the directory entry
de.Close();
This covers the problem of MSMQ not being installed and setting the quota value when once does not already exist. An additional issue is when the schema for your directory includes other organizational units. When this happens, the simplistic naming rules shown here do not find the correct computer objects. A better solution is to search for the computer in the directory. This can be done by using the DirectorySearcher class in the .Net Framework. A code sample to find the correct path to a computer within the domain can be found below.
// Find the domain we are working in
DirectoryEntry de = new DirectoryEntry("LDAP://rootDSE");
string root = de.Properties["defaultNamingContext"].Value.ToString();
de.Close();
// Query the domain for all the machines in the domain
de = new DirectoryEntry("LDAP://" + root);
DirectorySearcher ds = new DirectorySearcher(de,
string.Format("(&(objectCategory=computer)(CN={0}))",
txtFindComputer.Text));
SearchResultCollection coll = ds.FindAll();
// Validate there is only one item in the collection
if (coll.Count > 1)
{
// If more than one machine is found, abort processing.
// You could display a list of the machines found
// and let the user pick which one to adjust
MessageBox.Show(this, string.Format(
"{0} computers matched the computer name. Processing Aborted.",
coll.Count), "MSMQ Directory App",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
else if (coll.Count == 1)
{
// One computer found, populate our LDAP Object Path
DirectoryEntry targetComputer = coll[0].GetDirectoryEntry();
lblObjName.Text = targetComputer.Path.Insert(7, "CN=msmq,");
targetComputer.Close();
MessageBox.Show(this, string.Format(
"Computer {0} found. LDAP Object Path updated.",
txtFindComputer.Text), "MSMQ Directory App",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
else
{
// No computers found matching that name
MessageBox.Show(this, string.Format(
"No computers matched the computer name {0}. Processing Aborted.",
txtFindComputer.Text),
"MSMQ Directory App",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
de.Close();
I have updated the code sample below to include these updates as well. Enjoy!
Comments
- Anonymous
January 16, 2012
The comment has been removed - Anonymous
January 26, 2012
Found bug where I didn't correct the LDAP path to the object for the non-domain controller computer. Sorry for any problems.