I have a function that is used to purge a message queue on a machine but I'm looking to adapt it and make it a little more robust. I'd like to be able to fire the command to a machine even if the current machine doesn't have MSMQ installed.
The local command works without issue but when the invoke-command is called, the check to see if the queue exists returns false (even though the queue does exist). Has anyone run into anything like this before? Any suggestions?
This is my function:
Function Purge-MessageQueue
{
<#
.Synopsis
Use hostname to purge message queue
.DESCRIPTION
Checks if MSMQ is locally installed otherwise fire the purge
command to the machine you are purging
.EXAMPLE
Purge-MessageQueue -targetMachine $env:computername -queueName 'test'
#>
Param
(
[Parameter(Mandatory=$true)]
[String]$targetMachine,
[Parameter(Mandatory=$true)]
[string]$queueName
)
Write-Verbose "Purging $queueName queue on: $targetMachine"
$queueName = "$targetMachine\$queueName"
$error.clear()
[void] [Reflection.Assembly]::LoadWithPartialName("System.Messaging")
try {[void][System.Messaging.MessageQueue]::Exists($queueName)}
catch
{
if ($_.exception.ToString() -like '*Message Queuing has not been installed on this computer.*')
{
#push command to machine
$RemoteSuccess = Invoke-Command -ComputerName $targetMachine -ScriptBlock { Param($queueName)
[void] [Reflection.Assembly]::LoadWithPartialName("System.Messaging")
If([System.Messaging.MessageQueue]::Exists($queueName))
{
$queue = new-object -TypeName System.Messaging.MessageQueue -ArgumentList $queueName
Try{$queue.Purge()}
Catch{$error}
}
} -ArgumentList $queueName
}
}
If(!$error)
{
If([System.Messaging.MessageQueue]::Exists($queueName))
{
$queue = new-object -TypeName System.Messaging.MessageQueue -ArgumentList $queueName
$queue.Purge()
}
}
If(!$Error -and !$RemoteSuccess)
{
Write-Host "$queueName queue on $targetMachine cleared"
}
Else
{
Write-Warning "Failed locating queue $queueName on $targetMachine"
}
}
NOTES: In order to identify what exactly is going on, I used write-host on the exists statement and it returns false. The queue is not being found when I pass the scriptblock. It is executing on the other machine (tested writing a file which succeeded). When I run:
Write-Host "$([System.Messaging.MessageQueue]::Exists($queueName))`n$queueName"
$objqueue = new-object -TypeName System.Messaging.MessageQueue -ArgumentList $queueName
I get the false, the correct queue name, and the following error:
Exception calling "Purge" with "0" argument(s): "The queue does not exist or you do not have sufficient permissions to perform the operation." + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : MessageQueueException + PSComputerName : XXXXXX
Running the same command directly on the machine works without issue.
I also found someone else trying to do something similar on serverfault: https://serverfault.com/questions/399178/how-to-retrieve-names-of-all-private-msmq-queues-efficiently
And when I try this:
Invoke-Command -ComputerName $targetMachine -ScriptBlock { Get-MsmqQueue }
I get the following result:
Cannot find specified machine. + CategoryInfo : ObjectNotFound: (:) [Get-MsmqQueue], MessageQueueException + FullyQualifiedErrorId : MachineNotFound,Microsoft.Msmq.PowerShell.Commands.GetMSMQQueueCommand
This following command does return the data, but it doesn't allow me to send a purge command:
Invoke-Command -ComputerName $targetMachine -ScriptBlock {Get-WmiObject -class Win32_PerfRawData_MSMQ_MSMQQueue}
I also tried to write the content to a script file and then call the file, which when run on the machine, works without issue but not when called via invoke-command:
$filewriter = @"
[Reflection.Assembly]::LoadWithPartialName("System.Messaging")
If([System.Messaging.MessageQueue]::Exists('$queueName'))
{
`$objqueue = new-object -TypeName System.Messaging.MessageQueue -ArgumentList $queueName
Try{`$objqueue.Purge()}
Catch{`$error}
}
"@
$session = New-PSSession -ComputerName $targetMachine
Invoke-Command -Session $session -ScriptBlock {Param($FileWriter)
$FileWriter | Out-File "C:\Temp\PurgeQueue.ps1"
} -ArgumentList $filewriter
$test = Invoke-Command -Session $session -scriptblock {Pushd "C:\Temp\"
.\PurgeQueue.ps1}