Я хотел бы указать путь к очереди и получить количество сообщений. Любые советы о том, как это можно сделать?
Количество сообщений в MSMQ через Powershell
Ответы (12)
Это перечислит все очереди на машине и количество сообщений:
gwmi -class Win32_PerfRawData_MSMQ_MSMQQueue -computerName $computerName |
ft -prop Name, MessagesInQueue
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
, если эта функция уже установлена.
Итак, я увидел это: Что я могу сделать с 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');
И это сработало.
Решение, предложенное Irwin, меньше, чем идея.
Существует вызов .GetAllMessages
, который вы можете сделать, чтобы сделать это за одну проверку вместо цикла foreach.
$QueueName = "MycomputerName\MyQueueName"
$QueuesFromDotNet = new-object System.Messaging.MessageQueue $QueueName
If($QueuesFromDotNet.GetAllMessages().Length -gt $Curr)
{
//Do Something
}
.Length
дает вам количество сообщений в данной очереди.
следуя инструкциям по этой ссылке, вы можно использовать
$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
для удаленных очередей.
В расширениях сообщества PowerShell есть набор командлетов управления MSMQ. Попробуйте их и посмотрите, поможет ли какой-либо из них (вероятно, Get-MSMQueue):
Clear-MSMQueue
Get-MSMQueue
New-MSMQueue
Receive-MSMQueue
Send-MSMQueue
Test-MSMQueue
Примечание. Попробуйте скачать дистрибутив на основе модуля beta 2.0 — просто не забудьте «разблокировать» zip перед его распаковкой.
Используйте это для своего блока С#, чтобы получить счет. Он использует счетчик производительности для однократного запроса:
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, поскольку возвращает дополнительные данные сообщения, а затем подсчитывает элементы — ужасная производительность при любой реальной нагрузке.
Я искал повсюду информацию о доступе к очередям в кластере.
Для других, пытающихся использовать команды 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
Попробуйте один из этих...
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
}
Я искал хороший ответ на этот вопрос, и, хотя ответ Ирвина дал мне правильное основание, я искал какой-то код, который был бы немного больше похож на 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 $_
}
}
Его можно оптимизировать так, чтобы первая функция возвращала очереди вместо имен очередей, но мне нужны были оба для разных сценариев.
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
Это сработало для меня
[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
}