Re-play Production Suspended messages from start

This post is to simply describe how to pull out all messages from the suspended instances in Production.
I’ve been recently involve in remediation work for my client, where they have 50000+ suspended messages due to target system failure and timeouts. Since the design initially do not cater to re-submit these suspended instances, I need to look for other alternative. We took a back up of the Message box and copied re-stored to other similar environment. The task was to pull out one specific schema message to re-play these suspended again in the production.
I’ve came up with a small VB script to actually pull out all messages for the  particular schema from suspended instances in message box.

‘ save_messages.vbs
‘ Enter cscript save_messages.vbs with no arguments from a command prompt for usage
‘ This script needs to be run under a user account that is a member of the BizTalk Administrators
‘ group. This script needs to be run on a machine that is configured with BizTalk administration
‘ tools.

dim objBtsWmiNS, objMsg, svcinsts, inst, msg, ndx, size

Dim aryHostNames()
Dim aryObjQueues()
Dim aryHostBatchSize()

Dim strKey2Instance
Dim strQuery2Msg
Dim strServiceName
Dim strMsgType
Dim strSavePath

On Error Resume Next
Dim objArgs: Set objArgs = WScript.Arguments
If ( objArgs.Count = 0 OR objArgs.Count > 4) Then
PrintUsage()
wscript.quit 0
End If

wmiQuery = “”

‘ServiceStatus = 16 – ‘Completed With Discarded Messages’ in BizTalk Server 2004
‘ServiceStatus = 32 – ‘Suspended (not resumable)’
‘ServiceStatus = 4 – ‘Suspended (resumable)’
‘ServiceClass = 64 – ‘Routing Failure Report’
‘ErrorId = “0xC0C01B4C” – is how ‘Completed With Discarded Messages’ are exposed in BizTalk Server 2006

If (objArgs(0) = “-Z” OR objArgs(0) = “-z”) Then
wmiQuery = “select * from MSBTS_serviceinstance where ServiceStatus=16 OR ErrorId=’0xC0C01B4C'”
End If

If (objArgs(0) = “-A” or objArgs(0) = “-a”) Then
wmiQuery = “select * from MSBTS_serviceinstance where ServiceStatus=4 OR ServiceStatus=32 OR ServiceStatus=16 OR ErrorId=’0xC0C01B4C’ OR ServiceClass=64”
End If

If (objArgs(0) = “-SR” or objArgs(0) = “-sr”) Then
wmiQuery = “select * from MSBTS_serviceinstance where ServiceStatus=4 and ErrorDescription like ‘%ExceptionInformation%'”
End If

If (objArgs(0) = “-SNR” or objArgs(0) = “-snr”) Then
wmiQuery = “select * from MSBTS_serviceinstance where ServiceStatus=32”
End If

If (objArgs(0) = “-DIS” or objArgs(0) = “-dis”) Then
wmiQuery = “select * from MSBTS_serviceinstance where ServiceClass=32 AND ServiceStatus=8”
‘ServiceClass = 32 ‘Isolated Adapter
‘ServiceStatus = 8 ‘Dehydrated
End If

saveMessagesBeforeTermination = True

If ( objArgs.Count > 1) Then
strSavePath = objArgs(1)
End If

If ( objArgs.Count > 2) Then
strServiceName = objArgs(2)
End If

If ( objArgs.Count > 3) Then
strMsgType = objArgs(3)
End If

If(wmiQuery = “”) Then
PrintUsage()
wscript.quit 0
End If

wscript.echo “->Connecting to BizTalk WMI namespace”
Set objBtsWmiNS = GetObject(“WinMgmts:{impersonationLevel=impersonate, (security)}\\.\root\MicrosoftBizTalkServer”)
If Err <> 0 Then
CheckWMIError
wscript.quit 0
End If

wscript.echo “->Getting BizTalk host collection”
Set hosts = objBtsWmiNS.ExecQuery(“select * from MSBTS_HostSetting”)
If Err <> 0 Then
CheckWMIError
wscript.quit 0
End If

hostCount = hosts.count

ReDim aryHostNames(hostCount – 1)
ReDim aryObjQueues(hostCount – 1)
ReDim aryHostBatchSize(hostCount – 1)

wscript.echo “->Retrieve BizTalk host names and loading host queues”
ndx = 0
For Each host in hosts
wscript.echo “Found host ” & host.Properties_(“Name”)
aryHostNames(ndx) = host.Properties_(“Name”)
Set aryObjQueues(ndx) = objBtsWmiNS.Get(“MSBTS_HostQueue.HostName=””” & aryHostNames(ndx) & “”””)
If Err <> 0 Then
CheckWMIError
wscript.quit 0
End If
ndx = ndx + 1
Next

wscript.echo “->Getting collection of service instances”
Set svcinsts = objBtsWmiNS.ExecQuery(wmiQuery)

‘Iterate through instances and save them in host-specific arrays.

wscript.echo “->Start iterating service instances”
totalCount = 0
For Each inst in svcinsts
If (objArgs.Count = 1 Or (objArgs.Count > 1 And strServiceName = inst.Properties_(“ServiceName”) ) ) Then
wscript.echo “Found suspended instance “”” & inst.Properties_(“ServiceName”) & “”” on host ” & inst.Properties_(“HostName”)
‘Resolve host index
For hostIdx = 0 To hostCount-1
If aryHostNames(hostIdx) = inst.Properties_(“HostName”) Then
Exit For
End If
Next

’16 is an internal service class that cannot be terminated
If 16 = inst.Properties_(“ServiceClass”) Then
wscript.echo “Skipping BizTalk internal service instances (they cannot be terminated anyway)”
Else
’64 is a routing failure report and doesn’t have messages that can be saved
If 64 = inst.Properties_(“ServiceClass”) Or 16 = inst.Properties_(“ServiceClass”) Then
saveMessagesBeforeTermination = False
End If

errorCountSavingMessages = 0
If saveMessagesBeforeTermination Then

‘wscript.echo “Build Query”
If strMsgType > “” Then
strQuery2Msg = “select * from MSBTS_MessageInstance where ServiceInstanceID=””” & inst.Properties_(“InstanceId”) & “”” and MessageType = “”” & strMsgType & “”””
Else
strQuery2Msg = “select * from MSBTS_MessageInstance where ServiceInstanceID=””” & inst.Properties_(“InstanceId”) & “”””
End if

‘wscript.echo “Query is:” & strQuery2Msg

Set msgInsts = objBtsWmiNS.ExecQuery(strQuery2Msg)

For Each msg in msgInsts
msg.SaveToFile strSavePath

If Err <> 0 Then
CheckWMIError
wscript.echo “Failed to save MSBTS_MessageInstance”
wscript.echo Err.Description & Err.Number
errorCountSavingMessages = errorCountSavingMessages + 1
Else
wscript.echo “Saved message ” & msg.Properties_(“MessageInstanceID”)
End If
Next
End If
totalCount = totalCount + 1
End If

End If
Next

‘ Delete whatever is left
For hostIdx = 0 To hostCount-1
If aryHostBatchSize(hostIdx) > 0 Then
TerminateAccumulatedInstacesForHost hostIdx
End If
Next

wscript.echo “SUCCESS> ” & totalCount & ” instances were found and attempted to be saved”

‘This subroutine deals with all errors using the WbemScripting object.
‘Error descriptions are returned to the user by printing to the console.
Sub CheckWMIError()

If Err <> 0 Then
On Error Resume Next
Dim strErrDesc: strErrDesc = Err.Description
Dim ErrNum: ErrNum = Err.Number
Dim WMIError : Set WMIError = CreateObject(“WbemScripting.SwbemLastError”)

If (TypeName(WMIError) = “Empty” ) Then
wscript.echo strErrDesc & ” (HRESULT: ” & Hex(ErrNum) & “).”
Else
wscript.echo WMIError.Description & “(HRESULT: ” & Hex(ErrNum) & “).”
Set WMIError = nothing
End If

‘wscript.quit 0
End If

End Sub

Sub PrintUsage()
wscript.echo “Usage:”
wscript.echo “cscript save_messages.vbs < -Z | -A | -DIS | -SR | -SNR > SavePath [Port/Orchestration name] [MessageType]”
wscript.echo
wscript.echo ” -Z saves all “”Zombie”” instances (e.g. completed with discarded messages)”
wscript.echo ” -A saves all suspended and zombie instances as well as all routing failure reports”
wscript.echo ” -SR saves suspended resumable instances only”
wscript.echo ” -SNR saves suspended non-resumable instances only”
wscript.echo ” -DIS saves all dehydrated ‘isolated adapter’ instances”
wscript.echo ” optionally supply the name of the orchestration or port name to filter on specific instances”
wscript.echo
wscript.echo ” Ensure that the SavePath folder exists before running as that is where it saves the instances”
wscript.echo
wscript.echo ” Example: cscript save_messages.vbs -SR D:\temp\Suspended PublishInvoicePaymentStatusChange http://xyz/Channel/DynamicsAX/PaymentManagement/PublishInvoicePaymentStatusChange/v1#PublishInvoicePaymentStatusChange&#8221;
wscript.echo
End Sub

This Script can be called from the below batch file
cscript save_messages-CustomCluckHA.vbs -SR “C:\temp\Processor-SaveHASub_20151027” “Orchestration-TypName” “http://xyz/Assistance/Home/v1#HomeAssistAgreementChangedEvent&#8221;

After pulling out all the messages, we simply do the file drop in the production system. Our orchestrations cater for both one-way and two-way messaging patterns, so at the end it was easy.