Количество сообщений в MSMQ через Powershell

Я хотел бы указать путь к очереди и получить количество сообщений. Любые советы о том, как это можно сделать?


person Irwin    schedule 18.02.2010    source источник


Ответы (12)


Это перечислит все очереди на машине и количество сообщений:

gwmi -class Win32_PerfRawData_MSMQ_MSMQQueue -computerName $computerName |
    ft -prop Name, MessagesInQueue
person RobO    schedule 13.06.2011
comment
На самом деле я заметил, что вызов WMI не всегда перечисляет все очереди. Не уверен, почему. В итоге я вызвал [System.Messaging.MessageQueue]::GetPublicQueuesByMachine($machineName) для списка серверов, а затем использовал метод Irwin [QueueSizer]::GetMessageCount($queuepath) для получения количества сообщений для каждой очереди. - person RobO; 16.06.2011
comment
Есть ли способ получить из него больше, чем первые 100 сообщений? - person My Other Me; 08.12.2011
comment
К сожалению, это усекает имя очереди до 64 символов, а также возвращает только первые 97 результатов. :( - person Randy Burden; 10.05.2012
comment
@RobO, есть ли способ получить копию вашего полного сценария? Спасибо. - person mbourgon; 10.07.2013

PowerShell в Windows Server 2012/2012 R2 и Windows 8/8.1 имеет набор встроенных командлетов, которые можно использовать, установив компонент Microsoft Message Queue (MSMQ) Server Core.

# Get all message queues
Get-MsmqQueue;

# Get all the private message queues.
# Display only the QueueName and MessageCount for each queue.
Get-MsmqQueue -QueueType Private | Format-Table -Property QueueName,MessageCount;

Существует ряд других командлетов, которые можно использовать для управления очередями и создания сообщений. т.е.

  • New-MsmqQueue
  • Remove-MsmqQueue
  • Отправить-MsmqQueue
  • Receive-MsmqQueue
  • Get-MsmqQueueManager

Полный список справки по командлетам MSMQ см. в разделе Командлеты MSMQ в Windows PowerShell или Get-Command -Module MSMQ, если эта функция уже установлена.

person Bernie White    schedule 15.01.2014
comment
@RobertMooney Эта ссылка не работает. Да, нет встроенного параметра -ComputerName, который подключается к удаленному компьютеру, однако вы можете использовать удаленное взаимодействие PowerShell. - person Bernie White; 21.10.2015
comment
Однако обратите внимание, что командлет Get-MsMqQueue работает только с локальными очередями. См. technet.microsoft.com/en-us/ библиотека/hh405018(v=vs.85).aspx. - person Robert Mooney; 21.10.2015

Итак, я увидел это: Что я могу сделать с C# и Powershell? и перешел сюда:http://jopinblog.wordpress.com/2008/03/12/counting-messages-in-an-msmq-messagequeue-from-c/

И сделал это

# Add the .NET assembly MSMQ to the environment.
[Reflection.Assembly]::LoadWithPartialName("System.Messaging")

# Create a new QueueSizer .NET class help to warp MSMQ calls.
$qsource = @"
public class QueueSizer
    {
        public static System.Messaging.Message PeekWithoutTimeout(System.Messaging.MessageQueue q, System.Messaging.Cursor cursor, System.Messaging.PeekAction action)
        {
            System.Messaging.Message ret = null;
            try
            {
                // Peek at the queue, but timeout in one clock tick.
                ret = q.Peek(new System.TimeSpan(1), cursor, action);
            }
            catch (System.Messaging.MessageQueueException mqe)
            {
                // Trap MSMQ exceptions but only ones relating to timeout. Bubble up any other MSMQ exceptions.
                if (!mqe.Message.ToLower().Contains("timeout"))
                {
                    throw;
                }
            }
            return ret;
        }

        // Main message counting method.
        public static int GetMessageCount(string queuepath)
        {
            // Get a specific MSMQ queue by name.
            System.Messaging.MessageQueue q = new System.Messaging.MessageQueue(queuepath);

            int count = 0;

            // Create a cursor to store the current position in the queue.
            System.Messaging.Cursor cursor = q.CreateCursor();

            // Have quick peak at the queue.
            System.Messaging.Message m = PeekWithoutTimeout(q, cursor, System.Messaging.PeekAction.Current);

            if (m != null)
            {
                count = 1;

                // Keep on iterating through the queue and keep count of the number of messages that are found.
                while ((m = PeekWithoutTimeout(q, cursor, System.Messaging.PeekAction.Next)) != null)
                {
                    count++;
                }
            }

            // Return the tally.
            return count;
        }
    }
"@

# Add the new QueueSizer class helper to the environment.
Add-Type -TypeDefinition $qsource -ReferencedAssemblies C:\Windows\assembly\GAC_MSIL\System.Messaging\2.0.0.0__b03f5f7f11d50a3a\System.Messaging.dll

# Call the helper and get the message count.
[QueueSizer]::GetMessageCount('mymachine\private$\myqueue');

И это сработало.

person Irwin    schedule 18.02.2010
comment
+1 хороший ответ. Кроме того, не знаю почему, но мне пришлось изменить QueueSizer:: на [QueueSizer]:: в последней строке, чтобы этот скрипт работал. - person JohnD; 29.08.2013
comment
@JohnD +1 Квадратные скобки обозначают тип. Как вы сказали, требуется. Поскольку GetMessageCount является статическим методом, вам необходимо напрямую ссылаться на тип. Если бы это был метод экземпляра, вам пришлось бы сначала создать объект, например $qs = New-Object QueueSizer; затем укажите ссылку $qs.NetMessageCourt... - person Bernie White; 15.01.2014
comment
это ужасный ответ, так как он перебирает сообщения и подсчитывает их. Добавьте 1 000 000 сообщений в свою очередь и запустите это, и вы увидите, сколько времени это займет. - person Arijoon; 15.02.2018

Решение, предложенное Irwin, меньше, чем идея.

Существует вызов .GetAllMessages, который вы можете сделать, чтобы сделать это за одну проверку вместо цикла foreach.

$QueueName = "MycomputerName\MyQueueName" 
$QueuesFromDotNet =  new-object System.Messaging.MessageQueue $QueueName


If($QueuesFromDotNet.GetAllMessages().Length -gt $Curr)
{
    //Do Something
}

.Length дает вам количество сообщений в данной очереди.

person Clarence Klopfstein    schedule 18.03.2010
comment
но это безопасно? не будут ли оба этих решения потенциально блокировать другие процессы, читающие эту очередь? - person Roger; 19.08.2011
comment
Когда у вас есть очередь с десятками тысяч сообщений, производительность этого метода ужасна и не является хорошим вариантом. - person Randy Burden; 10.05.2012
comment
То же самое. Этот скрипт занимает гигабайты памяти для больших сообщений и длинных очередей - person infinity; 29.12.2012
comment
Найдите минутку и проголосуйте за два последних комментария (я только что это сделал). Это справедливая критика. Для вас двоих, какой вариант сработал для вас? Вы проголосовали за этот вариант? У вас есть лучший вариант? Я давно не работал с MSMQ и надеюсь, что больше никогда этого не сделаю :-) - person Clarence Klopfstein; 30.12.2012
comment
Это неэффективный способ получить количество сообщений, потому что он требует чтения всех сообщений и сохранения их в массиве, который находится в памяти. Это может привести к чрезмерному потреблению памяти в зависимости от частоты, размера сообщения и текущего количества сообщений в очереди и может повлиять на производительность приложения. Лучше использовать WMI: dejanstojanovic.net /aspnet/2018/январь/ - person maracuja-juice; 30.10.2018

следуя инструкциям по этой ссылке, вы можно использовать

$queues = Get-WmiObject Win32_PerfFormattedData_msmq_MSMQQueue
$queues | ft -property Name,MessagesInQueue

чтобы получить размер локальных очередей, или

$host = ...
$cred = get-credential
$queues = Get-WmiObject Win32_PerfFormattedData_msmq_MSMQQueue -computer $host -credential $cred
$queues | ft -property Name,MessagesInQueue

для удаленных очередей.

person Fabio Marreco    schedule 22.07.2014
comment
это отлично работало на старом сервере 2008 R2 без каких-либо новых командлетов - person rob; 15.03.2016

В расширениях сообщества PowerShell есть набор командлетов управления MSMQ. Попробуйте их и посмотрите, поможет ли какой-либо из них (вероятно, Get-MSMQueue):

Clear-MSMQueue
Get-MSMQueue
New-MSMQueue
Receive-MSMQueue
Send-MSMQueue
Test-MSMQueue

Примечание. Попробуйте скачать дистрибутив на основе модуля beta 2.0 — просто не забудьте «разблокировать» zip перед его распаковкой.

person Keith Hill    schedule 18.02.2010
comment
Требуемый PCX установлен? Я хочу только развертывание XCOPY для выполнения на удаленном сервере - person Kiquenet; 29.07.2014
comment
Более поздние версии PowerShell поставляются с модулем MSMQ, хотя я не знаю, доступен ли этот модуль только для Win8/Server2012. - person Keith Hill; 29.07.2014

Используйте это для своего блока С#, чтобы получить счет. Он использует счетчик производительности для однократного запроса:

public static int GetMessageCount(string machineName, string queuepath)
    {
        var queueCounter = new PerformanceCounter(
            "MSMQ Queue",
            "Messages in Queue",
            string.Format("{0}\\{1}", machineName, queuepath),
            machineName);

        return (int)queueCounter.NextValue();
    }

Это более эффективно, чем повторный просмотр, так как работа в основном выполняется на удаленной машине, а также более эффективно, чем GetAllMessages, поскольку возвращает дополнительные данные сообщения, а затем подсчитывает элементы — ужасная производительность при любой реальной нагрузке.

person bigwhitebyte    schedule 30.01.2017

Я искал повсюду информацию о доступе к очередям в кластере.

Для других, пытающихся использовать команды powershell в кластерных очередях:

На одном из узлов кластера:

$env:computername = "MsmqHostName"
Get-MsmqQueue | Format-Table -Property QueueName,MessageCount

удаленный от кластера:

Invoke-Command -ScriptBlock {$env:computername = "msmqHostName";Get-MsmqQueue | Format-Table -Property QueueName,MessageCount } -ComputerName ClusternNodeName
person housten    schedule 30.10.2019

Попробуйте один из этих...

function GetMessageCount2($queuename)
{
    $queuename = $env:computername + "\" + $queuename
    return (Get-WmiObject Win32_PerfFormattedData_msmq_MSMQQueue | Where-Object -filterscript {$_.Name -eq $queuename}).MessagesinQueue 
}

function GetMessageCount3($queuename)
{
    return (Get-MsmqQueue | Where-Object -FilterScript {$_.QueueName -eq $queuename}).MessageCount
}
person sevenfold    schedule 12.11.2014

Я искал хороший ответ на этот вопрос, и, хотя ответ Ирвина дал мне правильное основание, я искал какой-то код, который был бы немного больше похож на Powershell. Основная причина этого заключается в том, чтобы иметь дело с изменениями, поскольку вы не можете Add-Type несколько раз из-за того, что тип загружается в среде выполнения .Net, и не может быть выгружен без закрытия вашего экземпляра powershell.

Поэтому я взял его ответ и придумал:

# Add the .NET assembly MSMQ to the environment.
[Reflection.Assembly]::LoadWithPartialName("System.Messaging") | out-Null

function Get-QueueNames([Parameter(Mandatory=$true)][String]$machineName, [String]$servicePrefix)
{
    [System.Messaging.MessageQueue]::GetPrivateQueuesByMachine($machineName) |
        ForEach-Object { $_.Path } | 
        Where-Object { $_ -like "*$($servicePrefix).*" } 
}

function Get-MessageCount([parameter(Mandatory=$true)][String]$queueName)
{
    function HasMessage
    {
        param
        (
            [System.Messaging.MessageQueue]$queue,
            [System.Messaging.Cursor]$cursor,
            [System.Messaging.PeekAction]$action
        )

        $hasMessage = $false
        try
        {
            $timeout = New-Object System.TimeSpan -ArgumentList 1
            $message = $queue.Peek($timeout, $cursor, $action)
            if ($message -ne $null)
            {
                $hasMessage = $true
            }
        }
        catch [System.Messaging.MessageQueueException]
        {
            # Only trap timeout related exceptions
            if ($_.Exception.Message -notmatch "timeout")
            {
                throw
            }
        }

        $hasMessage
    }

    $count = 0
    $queue = New-Object System.Messaging.MessageQueue -ArgumentList $queueName
    $cursor = $queue.CreateCursor()

    $action = [System.Messaging.PeekAction]::Current
    $hasMessage = HasMessage $queue $cursor $action
    while ($hasMessage)
    {
        $count++
        $action = [System.Messaging.PeekAction]::Next
        $hasMessage = HasMessage $queue $cursor $action
    }

    $count
}

$machineName = "."
$prefix = "something"

Get-QueueNames $machineName $prefix |
    ForEach-Object {
        New-Object PSObject -Property @{
            QueueName = $_
            MessageCount = Get-MessageCount $_
        }
    }

Его можно оптимизировать так, чтобы первая функция возвращала очереди вместо имен очередей, но мне нужны были оба для разных сценариев.

person KallDrexx    schedule 15.01.2015

winrm s winrm/config/client '@{TrustedHosts="yourIp"}'
$securePassword = ConvertTo-SecureString "YourPassword" -AsPlainText -force
$credential = New-Object System.Management.Automation.PsCredential("Domain\Usernama",$securePassword)  
$session = New-PSSession YourIP -credential $credential
$command = {Get-WmiObject Win32_PerfFormattedData_msmq_MSMQQueue | ft -property Name,MessagesinJournalQueue,MessagesInQueue | out-String} 
Invoke-Command -session $session -scriptblock $command

введите здесь описание изображения

person Nuria12314    schedule 19.12.2015
comment
Здесь будут полезны некоторые комментарии. - person zero323; 20.12.2015

Это сработало для меня

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null

$AlertCount = 39

$queuePath = ".\private$\test.pdpvts.error"

$queue = New-Object System.Messaging.MessageQueue $queuePath


If($queue.GetAllMessages().Length -gt $AlertCount)
{
    Send-MailMessage -To "Me" -From "Alerts" -Subject "Message queue is full" -Credential mycridentials -UseSsl -SmtpServer mail.google.com
}
person Serge Voloshenko    schedule 28.10.2019