Save BizTalk Messages in C# .Net using PowerShell and BizTalkOperations Class - Part 1

Part 1 - Querying for Suspended Instances using PowerShell in a C# application

Sometimes you just want to get all the messages associated with a suspended BizTalk instance...say they get suspended at a point where an exception occurred and resuming only results in that same exception occurring again. My early BizTalk projects need some work :)

In any case, I looked at a few options for doing so:

  • you could go with querying the Tracking database directly using the built in bts_GetTrackedMessageParts stored procedure. But then you need to decompress the stream produced.
  • Then there is WMI (Windows Management Instrumentation) which to me, looked way too complicated and possibly slow
  • finally you can use a little combination of PowerShell and BizTalk.Operations

It sounds funny PowerShell? inside a C# application? Yup. In this post, we'll go over the PowerShell portion of the code.

All you need are the following dlls included in your project to use PowerShell:

using System.Management;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

Note

Here is how to add the System.Managment.Automation dll to your project:

In short

Another, and I think better, way to do it is to open your project file and in the first “<ItemGroup>” section, add:

<Reference Include="System.Management.Automation" />

This worked great for me.

The funny thing is, this PowerShell script is actually executing a WMI command, but it's actually much easier let PowerShell + the WMI command do the work rather than rolling your own WMI stuff. Here's the PowerShell part of it:

string script = @"get-wmiobject MSBTS_ServiceInstance -namespace 'root\MicrosoftBizTalkServer' -filter '(ServiceClass=1 or ServiceClass=4) and ServiceStatus = 4'";
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();

// instantiate PowerShell and run the script from above
PowerShell powerShell = PowerShell.Create();
powerShell.Runspace = runspace;
powerShell.AddScript(script);

Collection<PSObject> results = powerShell.Invoke();

After this runs, you'll have a Collection of PSObjects to do with what you want. In my case, I wanted to take those objects and pass them to the BizTalkOperations side of things to pull out suspended messages.

        int count = 0;
        int numPerDir =  Convert.ToInt32(ConfigurationManager.AppSettings["numFilesPerDirectory"]);

        foreach (PSObject result in results)
        {
            // split out the messages into directory chunks
            if (count % numPerDir == 0)
                saveChunk = count.ToString();

            Console.WriteLine(result.Properties["InstanceID"].Value);
            // Pass the suspended instanceID over to BizTalkOperations
            // This will grab all messages associated to this service instance
            Helpers.getAndSaveMessageswithOperations(
                result.Properties["InstanceID"].Value.ToString(),
                savePath + saveChunk,
                ConfigurationManager.AppSettings["MessageBoxDBName"]);

            if (count == numMessages)
                break;

            count++;
        }

        runspace.Close();

As you can see, we're now passing off the InstanceID to the Helpers.getAndSaveMessageswithOperations which is what we'll be covering next time. Here's a preview:

using Microsoft.BizTalk.Operations;
using Microsoft.XLANGs.BaseTypes;
using Microsoft.BizTalk.Message.Interop;

ServiceClass and ServiceStatus Values

Notice there are a couple filters on the get-wmiobject query: ServiceClass and ServiceStatus. Here are what those mean

//******** List of WMI Service Statuses ********
// ServiceClass = 1 (this gets Orchestration suspended instances)
// ServiceClass = 4 (messaging service instances).
//
// ServiceStatus = 1 - Ready To Run
// ServiceStatus = 2 - Active
// ServiceStatus = 4 - Suspended (Resumable)
// ServiceStatus = 8 - Dehydrated
// ServiceStatus = 16 - Completed With Discarded Messages' in BizTalk Server 2004
// ServiceStatus = 32 - Suspended (Not Resumable) 
// ServiceStatus = 64 - In Breakpoint