Getting Started
Architecture
NServiceBus
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

MSMQ Transport Scripting

Component: MSMQ Transport
NuGet Package: NServiceBus.Transport.Msmq (2.x)
Target Version: NServiceBus 8.x

This article contains code and scripts to facilitate deployment and operational actions with MSMQ.

These examples use the System.Messaging and System.Transactions assemblies.

The Systems.Messaging namespace is not available in .NET Core.
When using the C# code samples, be sure to add the proper includes for both the System.Messaging and System.Transactions assemblies in the program that's using these functions. When using the PowerShell scripts, include these assemblies by calling Add-Type in the script.

Create queues

Queue creation can be done for a specific endpoint or queues shared between multiple endpoints.

It may be necessary to script the creation of extra instance-specific queues. For example when using callbacks or scale-out based on sender-side distribution.

See also: Queue Permissions

The create queue helper methods

In C#

public static class QueueCreationUtils
{

    public static void CreateQueue(string queueName, string account)
    {
        var path = $@"{Environment.MachineName}\private$\{queueName}";
        if (!MessageQueue.Exists(path))
        {
            using (var messageQueue = MessageQueue.Create(path, true))
            {
                SetDefaultPermissionsForQueue(messageQueue, account);
            }
        }
    }

    static void SetDefaultPermissionsForQueue(MessageQueue queue, string account)
    {
        var allow = AccessControlEntryType.Allow;
        queue.SetPermissions(AdminGroup, MessageQueueAccessRights.FullControl, allow);

        queue.SetPermissions(account, MessageQueueAccessRights.WriteMessage, allow);
        queue.SetPermissions(account, MessageQueueAccessRights.ReceiveMessage, allow);
        queue.SetPermissions(account, MessageQueueAccessRights.PeekMessage, allow);
        queue.SetPermissions(account, MessageQueueAccessRights.GetQueueProperties, allow);
    }

    static string AdminGroup = GetGroupName(WellKnownSidType.BuiltinAdministratorsSid);

    static string GetGroupName(WellKnownSidType wellKnownSidType)
    {
        return new SecurityIdentifier(wellKnownSidType, null)
            .Translate(typeof(NTAccount))
            .ToString();
    }

}

In PowerShell

Function CreateQueue
{
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $QueueName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ValidateAccount -Account $_})]
        [string] $Account
    )

    $queuePath = '{0}\private$\{1}' -f $env:COMPUTERNAME, $QueueName

    if (-Not [System.Messaging.MessageQueue]::Exists($queuePath)) {
        $messageQueue = [System.Messaging.MessageQueue]::Create($queuePath, $true)
        SetDefaultPermissionsForQueue -Queue $messageQueue -Account $Account
    }
    else {
        Write-Warning "$queuepath already exists - no changes were made"
    }
}

Function GetAccountFromWellKnownSid
{
    param(
        [Parameter(Mandatory=$true)]
        [System.Security.Principal.WellKnownSidType] $WellKnownSidType
    )

    $account = New-Object System.Security.Principal.SecurityIdentifier $WellKnownSidType,$null
    return $account.Translate([System.Security.Principal.NTAccount]).ToString()
}

Function ValidateAccount {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $Account
    )

    # Test Account is valid
    $userAccount =  new-object System.Security.Principal.NTAccount($Account)
    try {
        [void] $userAccount.Translate([System.Security.Principal.SecurityIdentifier])
        return $true
    }
    catch [System.Security.Principal.IdentityNotMappedException] {
        Write-Warning "$account does not resolve to a Windows Account"
        return $false
    }
}

Function SetDefaultPermissionsForQueue
{
    param(
        [Parameter(Mandatory=$true)]
        [System.Messaging.MessageQueue] $Queue,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $Account
    )

    $adminGroup = GetAccountFromWellKnownSid -wellKnownSidType ([System.Security.Principal.WellKnownSidType]::BuiltinAdministratorsSid)
    $Queue.SetPermissions($AdminGroup, "FullControl", "Allow")
    $Queue.SetPermissions($Account, "WriteMessage", "Allow")
    $Queue.SetPermissions($Account, "ReceiveMessage", "Allow")
    $Queue.SetPermissions($Account, "PeekMessage", "Allow")
    $Queue.SetPermissions($Account, "GetQueueProperties", "Allow")
}

Creating queues for an endpoint

To create all queues for a given endpoint name.

In C#

public static void CreateQueuesForEndpoint(string endpointName, string account)
{
    // main queue
    QueueCreationUtils.CreateQueue(endpointName, account);

    // timeout queue
    QueueCreationUtils.CreateQueue($"{endpointName}.timeouts", account);

    // timeout dispatcher queue
    QueueCreationUtils.CreateQueue($"{endpointName}.timeoutsdispatcher", account);

    // retries queue
    // TODO: Only required in Versions 5 and below
    QueueCreationUtils.CreateQueue($"{endpointName}.retries", account);
}

In PowerShell

Function CreateQueuesForEndpoint
{
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $EndpointName,

        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ValidateAccount -Account $_})]
        [string] $Account,

        [Parameter(HelpMessage="Only required for NSB Versions 5 and below")]
        [Switch] $IncludeRetries
    )

    # main queue
    CreateQueue -QueueName $EndpointName -Account $Account

    # timeout queue
    CreateQueue -QueueName "$EndpointName.timeouts" -Account $Account

    # timeout dispatcher queue
    CreateQueue -QueueName "$EndpointName.timeoutsdispatcher" -Account $Account

    # retries queue
    if ($IncludeRetries) {
        CreateQueue -QueueName "$EndpointName.retries" -Account $Account
    }
}

Using the create endpoint queues

In C#

CreateQueuesForEndpoint(
    endpointName: "myendpoint",
    account: Environment.UserName);

In PowerShell

# For NServiceBus 6 Endpoints
CreateQueuesForEndpoint -EndpointName "myendpoint" -Account $env:USERNAME

# For NServiceBus 5 and below Endpoints
CreateQueuesForEndpoint -EndpointName "myendpoint" -Account $env:USERNAME -IncludeRetries

To create shared queues

In C#

QueueCreationUtils.CreateQueue(
    queueName: "error",
    account: Environment.UserName);

QueueCreationUtils.CreateQueue(
    queueName: "audit",
    account: Environment.UserName);

In PowerShell

CreateQueue -QueueName "error" -Account $env:USERNAME
CreateQueue -QueueName "audit" -Account $env:USERNAME

Delete queues

The delete helper queue methods

In C#

public static class QueueDeletionUtils
{
    public static void DeleteAllQueues()
    {
        var machineQueues = MessageQueue.GetPrivateQueuesByMachine(".");
        foreach (var q in machineQueues)
        {
            MessageQueue.Delete(q.Path);
        }
    }

    public static void DeleteQueue(string queueName)
    {
        var path = $@"{Environment.MachineName}\private$\{queueName}";
        if (MessageQueue.Exists(path))
        {
            MessageQueue.Delete(path);
        }
    }
}

In PowerShell

Set-StrictMode -Version 2.0

Add-Type -AssemblyName System.Messaging

Function DeleteQueuesForEndpoint
{
    param(
        [Parameter(Mandatory=$true)]
        [string] $endpointName
    )

    # main queue
    DeleteQueue $endpointName

    # timeout queue
    DeleteQueue ($endpointName + ".timeouts")

    # timeout dispatcher queue
    DeleteQueue ($endpointName + ".timeoutsdispatcher")

    # retries queue
    # TODO: Only required in Versions 5 and below
    DeleteQueue ($endpointName + ".retries")
}

Function DeleteQueue
{
    param(
        [Parameter(Mandatory=$true)]
        [string] $queueName
    )

    $queuePath = '{0}\private$\{1}'-f [System.Environment]::MachineName, $queueName
    if ([System.Messaging.MessageQueue]::Exists($queuePath))
    {
        [System.Messaging.MessageQueue]::Delete($queuePath)
    }
}
Function DeleteAllQueues
{
    foreach ($queue in [System.Messaging.MessageQueue]::GetPrivateQueuesByMachine("."))
    {
        [System.Messaging.MessageQueue]::Delete($queue.Path)
    }
}

To delete all queues for a given endpoint

public static void DeleteQueuesForEndpoint(string endpointName)
{
    // main queue
    QueueDeletionUtils.DeleteQueue(endpointName);

    // timeout queue
    QueueDeletionUtils.DeleteQueue($"{endpointName}.timeouts");

    // timeout dispatcher queue
    QueueDeletionUtils.DeleteQueue($"{endpointName}.timeoutsdispatcher");

    // retries queue
    // TODO: Only required in Versions 5 and below
    QueueDeletionUtils.DeleteQueue($"{endpointName}.retries");
}
DeleteQueuesForEndpoint("myendpoint");

To delete shared queues

QueueDeletionUtils.DeleteQueue(queueName: "error");
QueueDeletionUtils.DeleteQueue(queueName: "audit");

Related Articles