如何使用 PowerShell 从 MSMQ 消息队列中删除特定消息

Posted

技术标签:

【中文标题】如何使用 PowerShell 从 MSMQ 消息队列中删除特定消息【英文标题】:How to use PowerShell to delete specific messages from an MSMQ message queue 【发布时间】:2016-09-23 16:02:10 【问题描述】:

我正在尝试使用 PowerShell 从 MSMQ 消息队列中删除特定消息。我知道 PowerShell 4+ 中引入了几个用于管理 MSMQ 队列和消息的新 cmdlet,但据我所知,这些仍然无法帮助我实现删除特定消息的目标。

我想要实现的是一个连接到指定队列的简单脚本,然后遍历该队列中的每条消息,在消息正文中查找指定的搜索字符串,然后 MOVES 任何匹配的消息到同一服务器上的另一个队列。我可以很好地搜索消息,并且可以使用 Send 方法复制任何匹配项:

$source = new-object System.Messaging.MessageQueue($sourcequeuename)
$destination = new-object System.Messaging.MessageQueue($destinationqueuename)
$msgs = $source.GetAllMessages()
foreach ( $msg in $msgs )

    #Extra logic here - check message body for search string etc...
    $destination.Send($msg)

但是 - 一旦复制,我从源队列中删除原始消息的唯一选择似乎是清除 整个 源队列,这也会删除所有其他消息,我不会想做!

$source.Purge()

我以为我正在使用新的 (PowerShell 4+) 'Move-MsmqMessage' cmdlet...

Move-MsmqMessage -DestinationQueue $d -InputObject $q -Message $msg

但我正在努力让它工作 - 我不清楚我是否可以将特定的消息对象传递给它以移动。谁能给我一个使用 PowerShell(任何版本)循环队列中的消息并使用此 Move-MsmqMessage cmdlet 移动特定消息的工作示例?

【问题讨论】:

您不能将消息移出队列。您只能使用原始内容创建新消息以发送到不同的队列,然后删除原始消息。可能听起来很迂腐,但 MSMQ 的概念是目标队列是消息的最终存放位置。有一个确认传递到队列的基本机制和超时。如果您可以移动消息,那么该机制必须以某种方式跟踪该活动(跨多台机器!)并每次通知原始发件人。 Move-MsmqMessage 仅通过使用子队列影响同一队列中的消息。一个队列可以分为许多子队列,但所有消息仍然有效地在同一个队列中。 感谢约翰,让我更清楚了 【参考方案1】:

未经测试,但您应该可以使用ReceiveById 函数删除消息:

foreach ( $msg in $msgs )

   #Extra logic here - check message body for search string etc...
   $source.ReceiveById($msg.Id, [timespan]::FromMinutes(1))

【讨论】:

这成功了!然后调用 $destinationqueue.Send($msg) 我得到了我想要的有效动作。原始消息从源队列中删除,副本出现在目标队列中。我尝试在 ReceivebyId 函数之前调用 .Send,但脚本一直挂起,然后报告超时。在我已经收到/删除源之后,我不太明白如何复制消息,但我认为这是因为在我的完整脚本中,我将所有消息加载到 $msgs = $q.GetAllMessages() 中,所以复制使用的是变量中的内容而不是实际的源消息? 是的,它可能使用变量中的消息。但是我不知道为什么如果你这样做会超时。【参考方案2】:

问题和答案不包含使用的完整脚本。这是我用来从队列中删除单个消息的完整脚本,一旦我知道消息的 Id。

 [System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") 
 $queuePath = "FormatName:DIRECT=OS:MachineName\private$\NameOfQueue" 
 $queue = New-Object System.Messaging.MessageQueue $queuePath 
 $poisonMessageId = "d53df8ba-3b6a-418b-ab27-198655534253\39996" 
 $queue.ReceiveById($poisonMessageId) 

顺便说一句,找到消息 ID 很容易,顺便说一句。 去寻找消息: 计算机管理 -> 服务和应用程序 -> 消息队列 -> 专用队列。 打开包含您要删除的消息的私人队列 选择“属性”并在“常规”选项卡中显示消息 ID。

【讨论】:

【参考方案3】:

Jay Dubya 脚本的扩展版本,按模式删除

$StringToFind = "AMS1-COMET5"
$QueueName = "AMS1-COMET5"

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging")
$queuePath = "FormatName:DIRECT=OS:"+ [System.Net.Dns]::GetHostName() + "\private$\" + $QueueName
$queue = New-Object System.Messaging.MessageQueue $queuePath 
$SrcQueue = Get-MsmqQueue($QueueName)
$Messages = $SrcQueue | Receive-MsmqQueue -Peek -Count 10000000
$Messages |foreach 
    if ($_.Label -match $StringToFind) 
        $_.Label
        $queue.ReceiveById($_.Id) 
        

【讨论】:

以上是关于如何使用 PowerShell 从 MSMQ 消息队列中删除特定消息的主要内容,如果未能解决你的问题,请参考以下文章

我们如何加快从 MSMQ 接收消息的速度?

如何在C#中使用MSMQ

如何在 C# 中使用 MSMQ

如何并行处理 MSMQ 消息

MSMQ消息队列的安装启用

什么是 Microsoft 消息队列 (MSMQ)?它是如何工作的?