PowerShell for BizTalk Server

During my preparation for my Tech Ed talk on BizTalk Server port binding options, I wanted to write a PowerShell script to help me manage the transitions from one demo to another.  For the most part, I was looking for a way to quickly enable / disable receive locations and start / unenlist send ports and orchestrations.  All of this is available in WMI, but I wanted to make some reusable functions in PowerShell so I didn't have to drop into WMI each time I wanted to do it.  I wanted a simple function I could call like so:

EnableReceiveLocation("MYRL")

 

It turns out that creating these functions in a script file is relatively easy.  One issue I ran into, however, is that transitions for send ports and orchestrations are not as straight forward as they are in the UI.  In the UI if a port is unenlisted, I can simply start it.  Under the covers, however, the admin tool is actually enlisting and then starting.  So, in code, I have to call the operations to both enlist and start.  Or, if the port is already enlisted, but not started, then in a function called StartSendPort, I have to just start it.  So there is some checking of the current status rather than just blindly wrapping WMI calls.  You'll need to check the docs in some situations to get the enum values.  I used the hard coded values in my case. 

 

function StartSendPort{
    param([string]$portName)

    $sp = Get-WmiObject MSBTS_SendPort -n root\MicrosoftBizTalkServer -filter "Name='$portName'"

    if($sp -ne $null)
    {
        if($sp.Status -eq 1 -or $sp.Status -eq 2)
        {
            if($sp.Status -eq 1)
            {
                $null = $sp.Enlist()
            }
            $null = $sp.Start()
            Write-Host "Started send port: " + $portName -fore Green
        }
        else
        {
            Write-Host "Send port " + $portName + " is already started." -fore Yellow
        }
    }
    else
    {
        Write-Host "Send port not found" -fore Red
    }
}

 

Where things got a little more challenging was when I wanted to start working with applications.  Applications provide a nice way to manage a group of ports by allowing start/stop functionality; unfortunately, the application is not surfaced through WMI.  Never fear however, b/c PowerShell is built on top of .NET.  All I needed to do was create an instance of the BtsCatalogExplorer class and then I was on my way to managing the applications.  But first, I had to load the assembly that included that class.  I chose to do that using the path, but strong names works very well too.  Then I used the New-Object cmdlet to create an instance and navigate to the application. 

 

[System.Reflection.Assembly]::LoadFrom("C:\Program Files\Microsoft BizTalk Server 2006\Developer Tools\Microsoft.BizTalk.ExplorerOM.dll")

function StopBTSApplication
{
    param([string]$appName)

    $exp = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer
    $exp.ConnectionString = Get-BTSConnectionString
    $app = $exp.Applications[$appName]
    if($app -eq $null)
    {
        Write-Host "Application " $appName " not found" -fore Red
    }
    else
    {
        if($app.Status -ne 2)
        {
            #full stop of application
            $null = $app.Stop(63)
            $null = $exp.SaveChanges()
            Write-Host "Stopped application: " $appName
        }
    }

}

 

And, because I was trying not to hard code too much, I create the connection string using WMI to get the group settings. 

function Get-BTSConnectionString
{
    $group = Get-WmiObject MSBTS_GroupSetting -n root\MicrosoftBizTalkServer
    $dbName = $group.MgmtDBName
    $server = $group.MgmtDBServerName
    [System.String]::Concat("server=", $server, ";database=", $dbName, ";Integrated Security=SSPI")
}

 

Notice that I simply execute the Concat to get the connection string, and because this results in a new string, that value is returned to the pipeline and available to be set in a variable or used in a cmdlet. 

I'm loving the stuff I can do with PowerShell and feel like I'm just scratching the surface.  Hope this helps someone else get a jumpstart as well.  I've attached the PowerShell file with my functions included. 

Attachment: BizTalk_PowerShell.ps1.txt


Posted Jun 26 2008, 10:29 PM by matt-milner
Filed under:

Comments

moshe ro wrote re: PowerShell for BizTalk Server
on 07-13-2008 8:45 AM

Hi,

I succeded to implement the "start application" on my develope machine .

However ,when I tried to implement it on the run time machine (64 bit) ,I got :

New-Object : Exception calling ".ctor" with "0" argument(s): "Explorer OM is not supported in a 64bit process."

At C:\PS1\Test\stop_app1.ps1:16 char:19

+     $exp = New-Object  <<<< Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer

Property 'ConnectionString' cannot be found on this object; make sure it exists and is settable.

At C:\PS1\Test\stop_app1.ps1:17 char:7

+     $exp.C <<<< onnectionString = Get-BTSConnectionString

Cannot index into a null array.

At C:\PS1\Test\stop_app1.ps1:18 char:27

+     $app = $exp.Applications[$ <<<< appName]

matt-milner wrote re: PowerShell for BizTalk Server
on 07-13-2008 3:34 PM

Moshe,

You'll need to run the script in the 32 bit version of PowerShell.  If you look on your start menu, you should see under the Windows PowerShell folder that you have both the 64 bit and the 32 bit versions.  If you run the script in the 32 bit version, then you should be OK.  

Matt

Peter Golconda wrote re: PowerShell for BizTalk Server
on 07-21-2008 5:22 PM

I could implement it and create an admin app (.net) for my company so that any support person (without much biztalk experience) will be able to support.  Thanks for  the code.

moshe ro wrote re: PowerShell for BizTalk Server
on 07-23-2008 1:10 PM

Hi,

you were write ,I run the script in 32 bit version of PowerShell ,and then it succeded to run .

However ,when I tried to implement your code ,I got an answer that it failed .

from the failure ,I understand that it tried to stop all the application ,while I tried to stop only spedific application (EAI_NumberManagement).

This is the example :

**********************

[System.Reflection.Assembly]::LoadFrom("C:\Program Files (x86)\Microsoft BizTalk Server 2006\Developer Tools\Microsoft.BizTalk.ExplorerOM.dll")

function Get-BTSConnectionString

{

$group = Get-WmiObject MSBTS_GroupSetting -n root\MicrosoftBizTalkServer

$dbName = $group.MgmtDBName

$server = $group.MgmtDBServerName

[System.String]::Concat("server=", $server, ";database=", $dbName, ";Integrated Security=SSPI")

}

function StopBTSApplication

{

$appName="EAI_NumberManagement"

$exp = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer

$exp.ConnectionString = Get-BTSConnectionString

$app = $exp.Applications[$appName]

if($app -eq $null)

{

Write-Host "Application " $appName " not found" -fore Red

}

else

{

if($app.Status -ne 2)

{

#full stop of application

$null = $app.Stop(63)

$null = $exp.SaveChanges()

Write-Host "Stopped application: " $appName

}

}

}

StopBTSApplication

******************************

The output was:

Exception calling "SaveChanges" with "0" argument(s): "Could not stop orchestration 'EAI_AQRetry_Orchs.ArmAQRetry_Orch,

EAI_AQRetry_Orchs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=267fe1f0f0549c16'. Orchestration(s) 'EAI_ATGW_Orchs

.Async_TGW_Main_Orch : EAI_ATGW_Orchs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=267fe1f0f0549c16', 'EAI_ATGW_Or

chs.Async_TGW_Transportation_Orch : EAI_ATGW_Orchs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=267fe1f0f0549c16'

is(are) started which depend(s) upon this orchestration."

At C:\temp\stop_app.ps1:28 char:28

+             $null = $exp.SaveChanges( <<<< )

matt-milner wrote re: PowerShell for BizTalk Server
on 07-23-2008 1:22 PM

Moshe,

It looks as if you might have case where an orchestration in another application has a dependency on an orchestration in your current application. If that is the case, then use the function to unenlist the relying orchestration, then stop your application.  A test for this would be to make sure the relying orchestration is started and try to do a stop of your application in the admin console.  You should get the same error.  

moshe ro wrote re: PowerShell for BizTalk Server
on 07-24-2008 9:39 AM

Hi,

I don't think this is the case

I have checked it:

I verify that all the orchs are started .

Then I made a stop (Full stop) to my specific application (using admin console).

This stop (using admin console)  worked successfull

without errors

matt-milner wrote re: PowerShell for BizTalk Server
on 07-24-2008 9:58 AM

Moshe,

After you do the full stop in the admin console, what is the state of the orchestrations in your other application that depends on the orchestration in the application you are stopping.

EAI_ATGW_Orchs.Async_TGW_Main_Orch, EAI_ATGW_Orchs

AND

EAI_ATGW_Orchs.Async_TGW_Transportation_Orch, EAI_ATGW_Orchs

Are they stopped or unenlisted? Perhaps the admin console is doing some work behind the scenes for you that you'll need to do manually with the object model (i.e. stopping or unenlisting those orchestrations that depend on the one you are unenlisting).  

As far as I know, choosing a specific application by name will not get more than one application, and as you can see from the script, it does not iterate over the results.  So any dependencies are baked into using explorer object model to manage applications.  In other words, I think you'd see this in a C# application as well.  

moshe ro wrote re: PowerShell for BizTalk Server
on 07-28-2008 8:01 AM

Hi Matt,

After I did a full stop in the admin console to my application ,the other Orchs (EAI_ATGW*) status in my other application is still started.

Is it possible that you copy the example code that I wrote on 23/7 ,and run it  ? (perhaps something is missing in the script)

matt-milner wrote re: PowerShell for BizTalk Server
on 07-28-2008 12:07 PM

Moshe,

I don't see anything wrong with the script.  When I run with dependencies on my machine, I get that error regardless of whether I use the admin console or the script / API.  Keep in mind that the admin console does let you select (on another tab) referencing applications to stop when you stop one application.  If you have that set, it might be trying to stop both in the console, but not in the script.  

I'm not sure how your orchestrations reference each other (do they use a Call or Start orchestration) but that might have something to do with it as well.  In my tests I just use dependencies of artifacts that are found in the admin console; depending on a send port in another app for instance.

Have you tried writing the script that unenlists the depending orchestrations first, then stopping your application?  That should definitely work.

I'm not sure what other help I can give as I can't reproduce your problem on my end.  Sorry.  

Matt

moshe ro wrote re: PowerShell for BizTalk Server
on 07-29-2008 1:24 PM

Hi Matt ,

Thanx for your patience .

I would appreciate ,if you just explain what is the "63"

from $null = $app.Stop(63) stands for ? ,and what is the

source of getting this value(63)

matt-milner wrote re: PowerShell for BizTalk Server
on 07-29-2008 1:54 PM

Moshe,

that value comes from the enum ApplicationStopOption

public enum ApplicationStopOption

{

   DisableAllReceiveLocations = 8,

   StopAll = 0x3f,

   StopReferencedApplications = 0x20,

   UndeployAllPolicies = 0x10,

   UnenlistAllOrchestrations = 1,

   UnenlistAllSendPortGroups = 4,

   UnenlistAllSendPorts = 2

}

this enum supports the "flags" option so it can bitwised together.  You might want to try a value of 15 (0x0f) to stop everything but policies and referenced applications.  This may be part of your problem.  

The docs for the enum are at:

technet.microsoft.com/.../microsoft.biztalk.explorerom.applicationstopoption.aspx

Hope this helps.  

Matt

moshe ro wrote re: PowerShell for BizTalk Server
on 07-30-2008 12:23 AM

Hi Matt.

I set the value to 15 (as you recommended) and it solved the problem :-) .

Your implementation save me the amounr of code that involves the need to unenlist each orch within a given dll ,and the  dependency  calculation of each orchs (inside the given dll).

I want to thank you ,and apologize for bothering you and your blog.

thanx and regards

moshe ro

moshe ro wrote re: PowerShell for BizTalk Server
on 07-30-2008 3:09 AM

Hi Matt.

I'm tring to implement the start function

I tried to figure where did u get the "public enum " values ,but I didn't find .

I found in msdn.microsoft.com/.../microsoft.biztalk.applicationdeployment.applicationstopoption.aspx that "This enumeration supports the BizTalk Server 2006 infrastructure and is not intended to be used directly from your code."

My qeustion is ,How can I use the member name I.S.O the enum values ?

I tried to run it like this way :

$null = $app.Stop(StopAll) .

But I got :

Missing `)` in Method call .

matt-milner wrote re: PowerShell for BizTalk Server
on 07-30-2008 9:02 AM

Moshe,

Glad it worked and that I could help.  It wasn't a bother at all, that's why I posted this stuff and this is good conversation.  

On using the Enums, you are right that the text value would be better.  In PowerShell, the way you do this is to wrap the name in quotes:

$null = $app.Stop("StopAll")

Then Powershell will try to convert that string to an enum value. As long as the string you are using matches one of the allowed values, it works like a charm.  

Thank for pointing that out, it is a nice improvement on the script for readability.  

Matt

Add a Comment

(required)  
(optional)
(required)  
Remember Me?