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

How to use PowerShell to delete specific messages from an MSMQ message queue

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

我想要实现的是一个连接到指定队列的简单脚本,然后遍历该队列中的每条消息,在消息正文中查找指定的搜索字符串,然后 将任何匹配的消息移动 到同一服务器上的另一个队列。我有这个非常适合搜索消息,并且可以使用 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 移动特定消息的工作示例?

未测试,但您应该可以使用 ReceiveById 功能删除消息:

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

问题和答案不包含使用的完整脚本。这是我用来从队列中删除单个消息的完整脚本,一旦我知道了消息的 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-198655534253996" 
 $queue.ReceiveById($poisonMessageId) 

顺便说一句,找到消息 ID 很容易,顺便说一句。 前往以下位置查找消息:
计算机管理 -> 服务和应用程序 -> 消息队列 -> 专用队列。
打开包含您要删除的邮件的私人队列
Select 'Properties' 并且在 'General' 选项卡中是消息 ID。

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) 
        }
}