Sunday, October 21, 2012

Removing Suspended Service Instances - BizTalk 2009

' 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

1 comment:

  1. if you want terminate the suspended instance from the SQL below query will help

    delete from InstancesSuspended where uidserviceid ='D8B7F7CB-B47A-4573-8567-CD987B0A8ABF'

    ReplyDelete