﻿# MSMQ Transport Scripting


This article contains code and scripts to facilitate deployment and operational actions with MSMQ.

These examples use the [System.Messaging](https://learn.microsoft.com/en-us/dotnet/api/system.messaging?view=netframework-4.8) and [System.Transactions](https://learn.microsoft.com/en-us/dotnet/api/system.transactions?view=netframework-4.8) assemblies.

> [!WARNING]
> The `System.Messaging` namespace is not available in .NET Core.

> [!NOTE]
> 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.

> [!NOTE]
> It may be necessary to script the creation of extra instance-specific queues. For example when using [callbacks](/nservicebus/messaging/callbacks.md#message-routing) or scale-out based on sender-side distribution.


See also: [Queue Permissions](/transports/msmq/index.md#permissions)


### The create queue helper methods


#### In C&#35;

<!-- snippet: msmq-create-queues -->

```cs
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();
    }

}
```

<!-- endsnippet -->


#### In PowerShell

<!-- snippet: msmq-create-queues-powershell -->

```ps1
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")
}
```

<!-- endsnippet -->


### Creating queues for an endpoint

To create all queues for a given endpoint name.


#### In C&#35;

<!-- snippet: msmq-create-queues-for-endpoint -->

```cs
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);
}
```

<!-- endsnippet -->


#### In PowerShell

<!-- snippet: msmq-create-queues-for-endpoint-powershell -->

```ps1
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
    }
}
```

<!-- endsnippet -->


### Using the create endpoint queues


#### In C&#35;

<!-- snippet: msmq-create-queues-endpoint-usage -->

```cs
CreateQueuesForEndpoint(
    endpointName: "myendpoint",
    account: Environment.UserName);
```

<!-- endsnippet -->


#### In PowerShell

<!-- snippet: msmq-create-queues-endpoint-usage-powershell -->

```ps1
# For NServiceBus 6 Endpoints
CreateQueuesForEndpoint -EndpointName "myendpoint" -Account $env:USERNAME

# For NServiceBus 5 and below Endpoints
CreateQueuesForEndpoint -EndpointName "myendpoint" -Account $env:USERNAME -IncludeRetries
```

<!-- endsnippet -->


### To create shared queues


#### In C&#35;

<!-- snippet: msmq-create-queues-shared-usage -->

```cs
QueueCreationUtils.CreateQueue(
    queueName: "error",
    account: Environment.UserName);

QueueCreationUtils.CreateQueue(
    queueName: "audit",
    account: Environment.UserName);
```

<!-- endsnippet -->


#### In PowerShell

<!-- snippet: msmq-create-queues-shared-usage-powershell -->

```ps1
CreateQueue -QueueName "error" -Account $env:USERNAME
CreateQueue -QueueName "audit" -Account $env:USERNAME
```

<!-- endsnippet -->


## Delete queues


### The delete helper queue methods


#### In C&#35;

<!-- snippet: msmq-delete-queues -->

```cs
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);
        }
    }
}
```

<!-- endsnippet -->


#### In PowerShell

<!-- snippet: msmq-delete-queues-powershell -->

```ps1
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)
    }
}
```

<!-- endsnippet -->


### To delete all queues for a given endpoint

<!-- snippet: msmq-delete-queues-for-endpoint -->

```cs
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");
}
```

<!-- endsnippet -->

<!-- snippet: msmq-delete-queues-endpoint-usage -->

```cs
DeleteQueuesForEndpoint("myendpoint");
```

<!-- endsnippet -->


### To delete shared queues

<!-- snippet: msmq-delete-queues-shared-usage -->

```cs
QueueDeletionUtils.DeleteQueue(queueName: "error");
QueueDeletionUtils.DeleteQueue(queueName: "audit");
```

<!-- endsnippet -->
