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