Powershell script to administer messages in BizTalk

The below script does everything from resume to terminate the suspended messages. It also allows you to get counts and save suspended messages into dedicated folders.

# Script to save, resume and list suspended messages. To be used by BizTalk admin ONLY!
# Created on 30/01/2014 by Dipesh A.
# Commands:
   # Note: CD to script path first.

    # To get count of all suspended messages
    # PS > .\GetSuspended.ps1 -action counts

    # To list all suspended messages
    # PS > .\GetSuspended.ps1 -action list

    # To save all suspended messages
    # PS> .\GetSuspended.ps1 -action save -path 'X:\[Path]'

    # To resume resumable suspended messages
    # PS> .\GetSuspended.ps1 -action resume

    # To terminate non-resumable suspended messages
    # PS> .\GetSuspended.ps1 -action terminate

# -----------------------------------------------------------------

# declare params: the action to take, and an optional
# path to save messages to
#
param(
    [string] $action=$(throw 'need action'),
    [string] $path=$(if ($action -eq 'save') { throw 'need path' })
)

#
# get all suspended messaging service instances,
# both resumable and not-resumable
#
function bts-get-messaging-svc-instances()
{
    get-wmiobject MSBTS_ServiceInstance `
    -namespace 'root\MicrosoftBizTalkServer' `
    -filter '(ServiceClass=1 or ServiceClass=4) and ServiceStatus = 4'
}

#

# save the message associated to the
# specified messaging Service Instance
#
function bts-save-message([string]$msgid, [string]$sname, $homepath)
{

    #save each message within respective folders.

    "msgid is $msgid"
    "ServiceName is $sname"
    "msg_counter is $counter"
    $msg = get-wmiobject MSBTS_MessageInstance `
    -namespace 'root\MicrosoftBizTalkServer' `
    -filter "ServiceInstanceID = '$msgid'"

    $newpath = (Join-Path $homepath $sname)
    "new path is $newpath"

    $r_code= (test-path $newpath)
    "return code is $r_code"

    if ($r_code -eq $False)
       {
       md $newpath
       "new directory created"
    }

    foreach($m in $msg)
    {
       $m.psbase.invokemethod('SaveToFile', ($newpath))
       "Message from ServiceInstanceID=$msgid saved to $newpath."
   }

}

#
# save the message associated to the
# specified messaging Service Instance
#
function bts-save-message1([string]$msgid)
{

    $msg = get-wmiobject MSBTS_MessageInstance `
    -namespace 'root\MicrosoftBizTalkServer' `
    -filter "ServiceInstanceID = '$msgid'"
    $msg.psbase.InvokeMethod('SaveToFile', ($path))
    "Message from ServiceInstanceID=$msgid saved."
}

#
# list resumable suspended instances
#
function bts-get-resumable-suspended()
{
    get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter 'ServiceStatus=4'
}

#
# list resumable suspended instances
#
function bts-get-nonresumable-suspended()
{
    get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter 'ServiceStatus=32'
}

#
# resume instance
#
function bts-resume-instance([string]$msgId)
{
    if(!($msgId -eq “”))
    {
       "Resume {0}" -f $msgId
       $msg = get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter “InstanceID = '$msgId'”
       $msg.Resume() | Out-Null
    "- Done"
    }
    else
    {
       "MessageId missing"
    }
}

#
# terminate non resumable instance
#
function bts-terminate-instance([string]$msgId)
{
    if(!($msgId -eq “”))
    {
       "Terminate {0}" -f $msgId
       $msg = get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter “InstanceID = '$msgId'”
       $msg.Terminate() | Out-Null
       "- Done"
   }
   else
    {
       "MessageId missing"
   }
}

#
# main script
#
switch ( $action )
{
    'counts' {
       bts-get-messaging-svc-instances |
       %{ $counter++; }

       "Total: $counter"

       $counterrr = 0
       bts-get-resumable-suspended | %{ $counterrr++; }

       "Resumable: $counterrr"

       $counternr = 0
       bts-get-nonresumable-suspended | %{ $counternr++; }

       "Non resumable: $counternr"
    }

   'list' {
        bts-get-messaging-svc-instances |
       fl InstanceId, ServiceName, SuspendTime, HostName,
       ServiceStatus, ErrorId, ErrorDescription
    }
    'save'
    {

       #Set home path
       $timestamp = Get-Date -UFormat "%Y%m%d%H%M%S"
       $newpath = (Join-Path $path $timestamp)
       "Home path is $newpath"

       $r_code= (test-path $newpath)
       "return code is $r_code"

       if ($r_code -eq $False)
       {
          md $newpath
          "new directory created"
       }

        #save summary
       $wmi = get-wmiobject MSBTS_ServiceInstance `
       -namespace 'root\MicrosoftBizTalkServer' `
       -filter '(ServiceClass=1 or ServiceClass=4) and ServiceStatus = 4' | out-string

       $file = New-Item -Type File -Name "Summary.txt" -Path $newpath
       Add-Content $file -Value $wmi

       bts-get-messaging-svc-instances |
       %{ $counter++; bts-save-message $_.InstanceID $_.ServiceName $newpath }

    }
    'resume'
    {
      bts-get-resumable-suspended | %{ bts-resume-instance($_.InstanceID) }
    }
    'terminate'
    {
      bts-get-nonresumable-suspended | %{ bts-terminate-instance($_.InstanceID) }
    }
}

ESB Portal with a bulk resubmission feature

The OTB ESB portal is quite handy but lacks some useful features and also has some usability issues.

I recently had a go at enhancing the ESB Management Portal so that messages can be resubmitted in bulk. This needed a bit of web skills as well in order to cater for the UI and make the whole experience seemless.
I needed to introduce two modes in the ‘Faults’ page where the user could view pending faults vs processed faults.

screen1

Users could select the faults for which they wanted the messages to be resubmitted and click on Resubmit.

screen2

Messages would then be resubmitted in the order same order they were thrown as exceptions.

screen3

This has really helped us in scenarios where a whole load of messages would be sent to the ESB portal for review and the administrator has to ensure that order of processing was maintained.

This feature involved changes to both the portal and the ESB exception service. The portal was also “ajaxified” for a better user experience.

BAMAlerts – The activation state cache could not be updated.

If you have log shipped or detached/attached the BAMAlerts databases, you will have issues starting the notification service on the BizTalk server for BAM alerts. The reason for this, when these databases are restored, the the ‘Cross-Database Ownership Chaining’ option on the BAMAlertsApplication and BAMAlertsNSMain databases is disabled and greyed out. Greyed out because it can only be enabled via a script.

cross_chaining

To enable these options, run the following command (you need to be sys-admin):

–set chaining for a database

alter database BAMAlertsApplication set DB_CHAINING ON

GO

alter database BAMAlertsNSMain set DB_CHAINING ON

GO

—-

Once done, you should be able to start the BAM alerts notification service on the BizTalk Server.

Determining Process IDs of multiple BizTalk Host Instances

For debugging, it is neccessary to attach the BizTalk host instance process to Visual Studio. However, if you have multple host instances, you cant tell which one is which.

I have found a PS script which gives you the process Ids of multiple host instances.
32Bit Hosts:
TASKLIST /FI “USERNAME ne NT AUTHORITYSYSTEM” /FI “IMAGENAME eq BTSNTSvc.exe” /SVC

64Bit Hosts:
TASKLIST /FI “USERNAME ne NT AUTHORITYSYSTEM” /FI “IMAGENAME eq BTSNTSvc64.exe” /SVC

SignalR & BizTalk

For those who have never heard about SignalR, it is an async .net library for building real-time web applications. This sounds so interesting that it can actually open another dimension for applications requiring realtime updates via BizTalk.

SignalR helps pushing data from the server to the client (not just browser clients). SignalR makes it dead easy and handles all the heavy lifting for you.

There is a very interesting article by Kent Weare which talks about SignalR and how it can be used with BizTalk.

http://kentweare.blogspot.com.au/2012/07/part-1-biztalk-signalr.html

Retry pattern and Suspend shape – the gotchas!

I have just come out a frustration moment with BizTalk where it was behaving differently when compared to a similar environment. I have a retry pattern in one of my orchestrations and a suspend shape within the catch block. See screenshot below:

One would hope that when the administrator resubmits the suspended message, it would continue from the point it left of (that is continue in the loop). However, what I saw was, the orchestration would go into the “active” state indefinately.  Also, when trying to terminate this active instance, the terminate job would show as pending and the service wouldnt terminate unless the host was restarted.

Further investigation revealed that the suspended orchestration has no related message (or context). See screenshot below.

To eliminate any false positives, I deployed the same app on our test environment and saw that there was a message linked to the suspended orchestration.

This is where I was stumped!

After hours of pondering, I thought of the famous MBV! I ran some analysis via the MBV and I found this in the report:

The value “Missing Restart Msg in the Spool table…” was the light at the end of the tunnel. I quickly ran the Terminator tool to clean the messagebox.

Once done, I ran the MBV analysis again and all critical warnings were gone in relation to “Control Messages”.

I then tried my test again and saw the messages were now linked to suspended orchestrations….

On resubmitting, I would see the message continue from where it left off…

Hope this helps someone having similar issues.

Tracing and Tracking ESB events

Many a times one may feel the need to trace ESB events when using itineraries. This will enable you to see how a message is getting processed by the ESB itinerary resolver and if something is going wrong there. The process of enabling this switch is quite simple and it involves the following:

Tracing

1) Open the BizTalk Configuration file, ie BTSNTSVC.exe.config

2) Add the following section (if one does not exist)  and save the file:

<system.diagnostics>

<sources>

<source name=”BizTalk ESB Toolkit 2.0″ />

</sources>

<switches>

<add name=”BizTalkESBToolkit20″ value=”4″ />

</switches>

<trace autoflush=”true” indentsize=”4″ >

<listeners >

<add name=”myListener”   type=”System.Diagnostics.EventLogTraceListener” initializeData=”BizTalk ESB Toolkit 2.0″ />

</listeners>

</trace>

</system.diagnostics>

Note: 
Add a Trace listener. If you don't already have a trace listener configured, add 1 of the many Trace listeners that come out of the box with the .Net framework: (Default, EventLog, TextWriter, Console, Text, etc.)
When using the EventLogTraceListener, the initializeData attribute must be set to the source of the Tracing Event. 
In this case it is the "BizTalk ESB Toolkit 2.0" source.

3) Restart the BizTalk Host Instance.

4) You will now see information and error events in the event viewer. Also if you have debugview running, you will see code traces there.

Tracking

After enabling tracing, you might still feel the need for tracking. That is, what went where? Every Itinerary Service has a property called ‘Tracking Enabled’ which you’ve got to set it to ‘True’ during the design phase. This sets the stage for tracking an Itinerary Service. Set this property for every single service in an Itinerary as this is false by default. Only those services whose ‘Tracking Enabled’ property is set to true will show up in the database.

Ok, tracking is set to true and my itinerary is deployed. Where do I see this tracing information?

When a service in an itinerary is set for tracking, it is recorded in the BAMPrimaryImport database in the table bam_ItineraryServiceActivity_Completed. the column itineraryBeginTime should be used to sort the results by datetime.

This table gives a snapshot view of the trajectory of the message and if each stage in its path was completed or pending.