TheGeekery

The Usual Tech Ramblings

PowerShell, and MSMQ

Over the last several months, we’ve been building out a second, and third, developerment and QA environment for our teams. Part of building out the environment, I started to look at ways of automating some of the server setup. One of the things we needed to automate was the configuration of MSMQ1. A bit of looking around, and I stumbled on a post from a Microsoft engineer. He has a quick script on how to create queues with Powershell.

The code makes use of the .NET framework, specifically the System.Messaging.MessageQueue library. Once I knew where to start, it was just a case of following Microsoft’s MSDN documentation down the rabbit hole. If you have ever had to look at the MSDN documentation, you’ll understand that it is very complete, and well structured. If we look at the documentation for this class, we see there are two methods to create a new queue. One method allows us to specify if the queue is transactional or not, the other implies a non-transactional queue.

$queue = [System.Messaging.MessageQueue]::Create('.\private\myqueue')
$t_queue = [System.Messaging.MessageQueue]::Create('.\private\my_tqueue', $true)

In the above 2 lines of code, I’m creating 2 different queues, one is not transactional (first statement), while the second is transactional. As the developers did not specify which way they wanted them, I left them as non-transactional.

So now we have the queues created, I needed to establish permissions. Again, looking at the methods for the MessageQueue class, we see a method called SetPermissions. There are 4 overloaded2 methods here that allow us to specify how the permissions are defined. I went with the last option that allowed us to specify the user/group/computer, rights, and type. This method accepts a string for the user, group, or computer. This is formatted like you would in any permission dialog. For example, if you are on a domain, and you wanted to grant a user access, you’d use the format “DOMAIN\username”, a computer entry would look like this “myserver$”.

Next you have to specify the access rights, this is done using System.Messaging.MessageQueueAccessRights. This defines what you want to grant access to, such as the ability to write messages.

The final entry in the method is the type of access. This is either allow, deny, set, or revoke, and is handled using the class System.Messaging.AccessControlEntryType. Allow, deny, and revoke are all pretty easy to understand, but Set is a little different. When used, it essentially wipes out all other permissions, and applies just the permission you are requesting.

So now we have all the permissions described, we end up doing something like this:

$queue.SetPermissions("Everyone", [System.Messaging.MessageQueueAccessRights]::GetQueueProperties, [System.Messaging.AccessControlEntryType]::Set)

This code removes all access to the “Everyone” group, and grants them the GetQueueProperties access only.

As I was creating several queues, and those queues all had the same permissions, it seemed logical to bundle them into a function, and a loop. The resulting code looked something like this:

[Void] [Reflection.Assembly]::LoadWithPartialName("System.Messaging")

function SetPermissions( $queue ) {
	$queue.SetPermissions(".\Administrators", [System.Messaging.MessageQueueAccessRights]::FullControl, [System.Messaging.AccessControlEntryType]::Set)

	$queue.SetPermissions("Everyone", [System.Messaging.MessageQueueAccessRights]::GetQueueProperties, [System.Messaging.AccessControlEntryType]::Set)
	$queue.SetPermissions("Everyone", [System.Messaging.MessageQueueAccessRights]::GetQueuePermissions, [System.Messaging.AccessControlEntryType]::Allow)
	$queue.SetPermissions("Everyone", [System.Messaging.MessageQueueAccessRights]::WriteMessage, [System.Messaging.AccessControlEntryType]::Allow)

	$queue.SetPermissions("SYSTEM", [System.Messaging.MessageQueueAccessRights]::ReceiveMessage, [System.Messaging.AccessControlEntryType]::Set)
	$queue.SetPermissions("SYSTEM", [System.Messaging.MessageQueueAccessRights]::PeekMessage, [System.Messaging.AccessControlEntryType]::Allow)
	$queue.SetPermissions("SYSTEM", [System.Messaging.MessageQueueAccessRights]::WriteMessage, [System.Messaging.AccessControlEntryType]::Allow)

	$queue.SetPermissions("LOCAL SERVICE", [System.Messaging.MessageQueueAccessRights]::ReceiveMessage, [System.Messaging.AccessControlEntryType]::Set)
	$queue.SetPermissions("LOCAL SERVICE", [System.Messaging.MessageQueueAccessRights]::PeekMessage, [System.Messaging.AccessControlEntryType]::Allow)
	$queue.SetPermissions("LOCAL SERVICE", [System.Messaging.MessageQueueAccessRights]::WriteMessage, [System.Messaging.AccessControlEntryType]::Allow)

	$queue.SetPermissions("ANONYMOUS LOGON", [System.Messaging.MessageQueueAccessRights]::ReceiveMessage, [System.Messaging.AccessControlEntryType]::Set)
	$queue.SetPermissions("ANONYMOUS LOGON", [System.Messaging.MessageQueueAccessRights]::PeekMessage, [System.Messaging.AccessControlEntryType]::Allow)
	$queue.SetPermissions("ANONYMOUS LOGON", [System.Messaging.MessageQueueAccessRights]::WriteMessage, [System.Messaging.AccessControlEntryType]::Allow)

	$computer = "{0}$" -f $env:COMPUTERNAME
	
	$queue.SetPermissions($computer, [System.Messaging.MessageQueueAccessRights]::GetQueueProperties, [System.Messaging.AccessControlEntryType]::Set)
	$queue.SetPermissions($computer, [System.Messaging.MessageQueueAccessRights]::GetQueuePermissions, [System.Messaging.AccessControlEntryType]::Allow)

}

$queues = 'logging','outboundcommands','requestcommands','responsecommands'

$queues | %{
	$queuename = ".\private$\{0}" -f $_
	$qb = [System.Messaging.MessageQueue]::Create($queuename)
	if ($qb -eq $null)
	{
		exit
	}
	$qb.label = $queuename
	
	SetPermissions $qb

}

As you can see, it’s rough around the edges; there is no error handling, and a lot of assumptions are made, but it works. This code creates 4 new queues in the private queue section of MSMQ; logging, outbound commands, requestscommands, and responsecommands. These queues are used by several different applications throughout the site. I’m going to work on cleaning it up, so it can be used as part of a new server deployment, which will check for queue existence, ensure certain windows features are enabled, and handle any errors that are kicked back when attempting to create the queues, or set the permissions.

Powershell, like many other scripting languages, makes easy work out of complex tasks. It is incredibly flexible and can do so much. What cool things have you used Powershell to do? How do you use it in automation?

  1. If you have never heard of it, Microsoft has good documentation on it. 

  2. If you’re not sure what overloading means, it basically allows you to specify the same method with different parameters, there is a nice example here

Comments