Removing Suspended Service Instances
Use the following code to delete suspended service instances.
' terminate.vbs
' Enter terminate.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, savemessages
Dim aryClassIDs()
Dim aryTypeIDs()
Dim aryInstanceIDs()
Dim aryHostNames()
Dim aryObjQueues()
Dim aryHostBatchSize()
Dim strKey2Instance
Dim strQuery2Msg
maxBatchSize = 200 'Terminate in batches. Max supported batch size is 2K-1 (2047)
On Error Resume Next
Dim objArgs: Set objArgs = WScript.Arguments
If ( objArgs.Count = 0 OR objArgs.Count > 2) 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 2009
If (objArgs(0) = "-Z" OR objArgs(0) = "-z") Then
wmiQuery = "select * from MSBTS_serviceinstance where ServiceStatus=16"
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"
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
If (objArgs(1) = "-NOSAVE" OR objArgs(1) = "-nosave") Then
saveMessagesBeforeTermination = False
Else
PrintUsage()
wscript.quit 0
End If
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)
ReDim aryClassIDs(hostCount, maxBatchSize-1)
ReDim aryTypeIDs(hostCount, maxBatchSize-1)
ReDim aryInstanceIDs(hostCount, maxBatchSize-1)
'Iterate through instances and save them in host-specific arrays.
'Terminate instances from host-specific array when array gets to a maxBatchSize
wscript.echo "-->Start iterating service instances"
totalCount = 0
saveMessages = saveMessagesBeforeTermination
For Each inst in svcinsts
saveMessagesBeforeTermination = saveMessages
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
strQuery2Msg = "select * from MSBTS_MessageInstance where ServiceInstanceID=""" & inst.Properties_("InstanceId") & """"
Set msgInsts = objBtsWmiNS.ExecQuery(strQuery2Msg)
For Each msg in msgInsts
msg.SaveToFile "C:\Temp"
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
If 0 = errorCountSavingMessages Then 'Only terminate when we had no problems saving messages
aryClassIDs(hostIdx, aryHostBatchSize(hostIdx)) = inst.Properties_("ServiceClassId")
aryTypeIDs(hostIdx, aryHostBatchSize(hostIdx)) = inst.Properties_("ServiceTypeId")
aryInstanceIDs(hostIdx, aryHostBatchSize(hostIdx)) = inst.Properties_("InstanceId")
aryHostBatchSize(hostIdx) = aryHostBatchSize(hostIdx) + 1 'Keep track of newly added instace for that host
Else
wscript.echo "Skipping the instance since couldn't save its messages"
End If
totalCount = totalCount + 1
If(aryHostBatchSize(hostIdx) = maxBatchSize) Then
TerminateAccumulatedInstacesForHost hostIdx
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 terminated"
Sub TerminateAccumulatedInstacesForHost(hostIdx)
wscript.echo "Sending termination request for host " & aryHostNames(hostIdx) & " service instances"
Dim aryClassIDs4Host()
Dim aryTypeIDs4Host()
Dim aryInstanceIDs4Host()
ReDim aryClassIDs4Host(aryHostBatchSize(hostIdx)-1)
ReDim aryTypeIDs4Host(aryHostBatchSize(hostIdx)-1)
ReDim aryInstanceIDs4Host(aryHostBatchSize(hostIdx)-1)
For i = 0 to aryHostBatchSize(hostIdx)-1
aryClassIDs4Host(i) = aryClassIDs(hostIdx, i)
aryTypeIDs4Host(i) = aryTypeIDs(hostIdx, i)
aryInstanceIDs4Host(i) = aryInstanceIDs(hostIdx, i)
Next
aryObjQueues(hostIdx).TerminateServiceInstancesByID aryClassIDs4Host, aryTypeIDs4Host, aryInstanceIDs4Host
CheckWMIError
aryHostBatchSize(hostIdx) = 0
End Sub
'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 Terminate.vbs < -Z | -A | -DIS | -SR | -SNR > [-nosave]"
wscript.echo
wscript.echo " -Z terminates all ""Zombie"" instances (e.g. completed with discarded messages)"
wscript.echo " -A terminates all suspended and zombie instances as well as all routing failure reports"
wscript.echo " -SR terminates suspended resumable instances only"
wscript.echo " -SNR terminates suspended non-resumable instances only"
wscript.echo " -DIS terminates all dehydrated 'isolated adapter' instances"
wscript.echo " -nosave terminates instances without saving messages they reference"
wscript.echo " Default action is to save instances to the C:\Temp folder on the local computer"
wscript.echo
wscript.echo " Ensure that the C:\Temp folder exists before running terminate if you want to save instances"
wscript.echo
wscript.echo " Example: cscript Terminate.vbs -z -nosave"
wscript.echo
End Sub