BizTalk SendPort Duplicator in PowerShell

How do you create an identical copy of a BizTalk SendPort except for the name?

It’s not uncommon for me to want create a duplicate of a SendPort, especially if it’s a more complicated SendPort like WCF or SQL with lots of parameters.

I finally wrote a PowerShell to do this. Maybe later, I’ll do the same for Receive Locations.

This script also demonstrates how to call BTSTask from PowerShell, and capture the results into a string. BtsTask is the command line tool that allows you to import and export bindings.

The script builds a binding file to add the new SendPort and optionally imports it. You can edit it on disk and manually import yourself if you want. You probably will change some of the other options (such as directory name if using the FILE adapter). You can do that in the disk file, or let the script import the bindings, and then make the changes in BizTalk Admin Console. Set the variable $ynImportNewSendPort to “Y” or “N” based on your preference.

Before running the script, find the five parameters (or just variables actually), and change them in the script below:

#SET THESE FIVE PARAMETERS
$applicationName = “MyCoolApplication”
$sqlServer = “YourServerName” #where the BizTalkMgmtDB is
$duplicateSendPortName = “sp_Archive”
$newSendPortName = “sp_Archive2”
$ynImportNewSendPort = “Y” #set to “Y” to auto-import the new SendPort, set to “N” if you want to edit it on disk

$BTSTaskFilePath = “e:\BizTalkServer2016\BTSTask.exe”

<pre>
<#

       Author: Neal Walters 
         Date: 04/15/2020 
  Description: Duplicate a BizTalk SendPort
         
      Details: User has to set five variables/parameters 
               (search for #SET THESE FIVE PARAMETERS). 

               Logic is as follows: 
               Export bindings, make a copy to work file, 
               remove each "collection", 
               pull out one SendPort, change it, put it back in, 
               and import new SendPort bindings. 
#>

function removeSection ($filename, $section) 
{
   $contents = [System.IO.File]::ReadAllText($filename)

   #Handle EmptyTag 
   $contents2 = $contents.Replace("<$section />", "") 
   if ($contents2 -eq $contents)
      {
           $contents = $contents2 

           #Handle non-EmptyTag
           $startPos = $contents.IndexOf("<$section") 
           $endPos = $contents.IndexOf("/$section>") 
           $endPos = $endPos + $section.Length 
           if ($endPos -gt $startPos) 
           {
              #Write-Host "$section : startPos=$startPos endPos=$endPos" 
              $contentsBefore = $contents.Substring(0,$startPos-1)
              $contentsAfter = $contents.Substring($endPos + 2) 
              $contents = $contentsBefore + $contentsAfter
           }
       }
       else 
       {
         $contents = $contents2 
       }
       [System.IO.File]::WriteAllText($filename, $contents) 
}

function AddSendPort ($filename, $sendPortXML) 
{
   $contents = [System.IO.File]::ReadAllText($filename)
   $contents = $contents.Replace("</Timestamp>","</Timestamp>`n`n<SendPortCollection>`n$sendPortXML`n</SendPortCollection>`n")
   [System.IO.File]::WriteAllText($filename, $contents) 
}

function getSendPort ($filename, $sendPortName) 
{
   $contents = [System.IO.File]::ReadAllText($filename)
   $startPos = $contents.IndexOf("<SendPort Name=`"$sendPortName`"") 
   $endPos = $contents.IndexOf("</SendPort",$startPos) 
   $extractLength = $endPos - $startPos + $section.Length + 11 
   $endPos = $endPos + $section.Length 
   #Write-Host "$section : startPos=$startPos endPos=$endPos Length=$extractLength" 
   $contentsSendPort = $contents.Substring($startPos, $extractLength) 
   return $contentsSendPort 
}

function fileReplace ($filename, $searchString, $replaceString) 
{
   $contents = [System.IO.File]::ReadAllText($filename)
   #Write-Host "fileReplace: Read Len of contents= $($contents.length)" 
   $contents = $contents.Replace($searchString, $replaceString) 
   #Write-Host $contents 
   #Write-Host "fileReplace: Write Len of contents= $($contents.length) from $filename" 
   [System.IO.File]::WriteAllText($filename, $contents) 
}

cls
$ErrorActionPreference = "Stop"
$formatDate = Get-Date -Format "yyyy-MM-dd hh:mm:ss"
Write-Host “Start: DateTime= $formatDate”

#------------------------------------------------------
#SET THESE FIVE PARAMETERS
$applicationName = "MyCoolApplication" 
$sqlServer = "YourServerName"    #where the BizTalkMgmtDB is 
$duplicateSendPortName = "sp_Archive" 
$newSendPortName       = "sp_Archive2" 
$ynImportNewSendPort = "Y"   #set to "Y" to auto-import the new SendPort, set to "N" if you want to edit it on disk 
#------------------------------------------------------

$formatDateTimeForFile = get-date -f yyyy_MM_dd
$username = $env:username
$exportFileNameOrig = "c:\Users\$username\AppData\Local\BizTalk\Binding Files\$applicationName.Binding_$formatDateTimeForFile.xml" 
$exportFileNameWork = "c:\Users\$username\AppData\Local\BizTalk\Binding Files\$applicationName.Binding_$($formatDateTimeForFile)_NewSendPort.xml" 

Write-Host $exportFileNameOrig
Write-Host $exportFileNameWork

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

$BTSTaskResults = &"$BTSTaskFilePath" ExportBindings /ApplicationName:$applicationName /Destination:"$exportFileNameOrig" /Server:"$SqlServer" /Database:BizTalkMgmtDb 
copy-item -Path $exportFileNameOrig -Destination $exportFileNameWork
Write-Host "============================================="
Write-Host "EXPORT RESULTS:" 
Write-Host $BTSTaskResults
Write-Host "============================================="

#call functions 
removeSection $exportFileNameWork "ModuleRefCollection" 
removeSection $exportFileNameWork "DistributionListCollection" 
removeSection $exportFileNameWork "ReceivePortCollection" 
fileReplace   $exportFileNameWork "<PartyCollection xsi:nil=`"true`" />" ""
$sendPortBindings = getSendPort $exportFileNameWork $duplicateSendPortName
$sendPortBindings = $sendPortBindings.Replace($duplicateSendPortName , $newSendPortName) 
Write-Host "sendPortBindings.Len=$($sendPortBindings.Length)" 
removeSection $exportFileNameWork "SendPortCollection" 
addSendPort $exportFileNameWork $sendPortBindings 

Write-Host "FileName: $exportFileNameWork" 
if ($ynImportNewSendPort -eq "Y")   
   {
        $BTSTaskResults = &"$BTSTaskFilePath" ImportBindings /ApplicationName:$applicationName /Source:"$exportFileNameWork" /Server:"$SqlServer" /Database:BizTalkMgmtDb 
        Write-Host "============================================="
        Write-Host "IMPORT RESULTS:" 
        Write-Host $BTSTaskResults
        Write-Host "============================================="
   }
else 
    {
       Write-Host "You have chose to manually edit the file (not imported into Biztalk)" 
    }

$formatDate = Get-Date -Format "yyyy-MM-dd hh:mm:ss"
Write-Host “End : DateTime= $formatDate”
</pre>

Here are references to other tools that do similar functions. I like the idea of having a simple script that I can customize as needed and I know exactly what it’s doing.

Sandro Pereira Port Multiplier Tool (Aug 2019)
Richard Seroter’s BizTalk Send Port Duplicator (from 2007)

Uncategorized  

Leave a Reply