I needed to implement RawString functionality to be able to read a non-XML file into an orchestration. Scott Colestock had a great article on this on his TraceOfThought blog, but when I needed it the other day, it had been hacked (hopefully only temporary).

1. Deploy the C# code towards the bottom of this log; it is not a pipeline, so can be added to new class to an existing C# helper library you might have, or you can put it in its own assembly.

2. Add a reference to this C# Assembly in your orchestration.

3. In your orchestration, create a multipart message type. It will have only one part, but that will be the RawString class from the code below.

4. In the orchestration, create a nessage of type System.Xml.XmlDocument, and assign this to your cativating receive. But wait Neal, I thought you said we wanted to receive a non-XML message. Trust me, this will work.

5. In the orchestration, add a Message Assignment shape and code similar to below:

//convert the message received to a new message with a multiple-part-type of RawString 
msg_rcv_RawString.MessagePart_1 = msg_XML_Doc; 

6. At this point, you can access the message as a string, for example:

varText = msg_rcv_RawString.MessagePart_1.ToString();

Voila – you have now have the text of the file in a variable called varText. You can then parse it, or do whatever you want with it.

The code below needs to be in a C# helper class that you can access within your orchestration. (Obviously give it a strong name and GAC it.) I can’t remember which site I got this code from, but I think it’s out there on several.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.IO;
using Microsoft.XLANGs.BaseTypes;

namespace REI.BizTalkNonDB.Helpers
{

    public abstract class BaseFormatter : IFormatter
    {
        public virtual SerializationBinder Binder
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public virtual StreamingContext Context
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public virtual ISurrogateSelector SurrogateSelector
        {
            get { throw new NotSupportedException(); }
            set { throw new NotSupportedException(); }
        }

        public abstract void Serialize(Stream stm, object obj);
        public abstract object Deserialize(Stream stm);
    }


    public class RawStringFormatter : BaseFormatter
    {
        public override void Serialize(Stream s, object o)
        {
            RawString rs = (RawString)o;
            byte[] ba = rs.ToByteArray();
            s.Write(ba, 0, ba.Length);
        }

        public override object Deserialize(Stream stm)
        {
            StreamReader sr = new StreamReader(stm, true);
            string s = sr.ReadToEnd();
            return new RawString(s);
        }
    }

    [CustomFormatter(typeof(RawStringFormatter))]
    [Serializable]
    public class RawString
    {
        [XmlIgnore]
        string _val;

        public RawString(string s)
        {
            if (null == s)
                throw new ArgumentNullException();
            _val = s;
        }

        public RawString()
        {
        }

        public byte[] ToByteArray()
        {
            return Encoding.UTF8.GetBytes(_val);
        }

        public override string ToString()
        {
            return _val;
        }
    }


}

Error:

the type or namespace ‘BaseCustomTypeDescriptor’ could not be found

Solution:

If you are working on BizTalk pipeline components, you may have copied over parts of c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler to your own solution or project. You either did not add the required project references, or some of the .cs file that are referenced. Specifically BaseCustomTypeDesciptor can be found in the FixMsgDescription.cs C# module.

Also: If you get error on “BitMap” could not be found, you need the System.Drawing namespace.

Below is a screen shot of the References you may need to add, and the .cs modules you might need to copy:

To add the reference, you can open the sample project, click the reference, and find the “Path” in the properties window. You can copy that path, then go to your project, and when you do an “Add Reference” you can browse to that path and select it.

Sometimes you ask yourself what version of BizTalk is running on a certain server. Maybe you’re a consultant or employee stepping into a new job/contract and you are trying to get the lay of the land. Or maybe you have some old servers that are not documented.

The following script will answer that question. Might save keystrokes of opeining Control Panel or RegEdit to find out.

See this page to get a list of all the BizTalk versions. Hope you don’t find anything older than BizTalk 2010!

cls
#read the registry 
$item = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\BizTalk Server\3.0"
Write-Host "Biztalk Internal Version: $($item.ProductVersion)"
$major,$minor, $x, $y = $item.ProductVersion.split('.') 
#Write-Host "$major $minor" 

# see https://social.technet.microsoft.com/wiki/contents/articles/7915.biztalk-server-versions.aspx 

$version = switch ($minor)
{
    13 {"2020"}  #assumed 
    12 {"2016"}
    11 {"2013/R2"}
    10 {"2013 (not R2)"}
    9 {"2010"} 
    8 {"2009"} 
    6 {"2006/R2"} 
    5 {"2006 (not R2)"} 
    0 {"2000-2004 Past Time to Upgrade! "} 
}

Write-Host "BizTalk Common Name: $version" 
Write-Host "Product Edition: $($item.ProductEdition)" 

Example Output:

Biztalk Internal Version: 3.10.229.0
BizTalk Common Name: 2013 (not R2)
Product Edition: Enterprise

BizTalk has a schedule job that does incremental backups, usually every 15 minutes. But what if you want to do a full backup immediate?

Run this command in SQL Server Management Studio (SSMS):

USE BizTalkMgmtDb
EXEC sp_ForceFullBackup

Then manually start the SQL agent job “Backup BizTalk Server (BizTalkMgmtDb)” (or wait until the next scheduled 15 minute interval).

The above is required if you get in the situation where you see this error in the 3rd step of the above backup agent job:

Error: BACKUP LOG cannot be performed because there is no current database backup.

Full error looks something like this:

Send Port: “sp_Vendor_Vendor_FilesToSendToAS2” URI: “http://as2.vendorsite.com/”
Reason: The Encryption Certificate has not been configured for AS2 party. AS2-From: YourAS2ID AS2-To: VendorAS2ID

Solution:
Open the send port, click the “Certificate” item on the left.
Then click the “Browse” button under the certificate, and select the certificate that applies to your vendor. The certificate has to be first stored in the “Local Computer/Other People Store”, as described on this MSDN doc.

The selection for the certificate will look something like this. I had to black out our actual vendor/certificate names.

test

This script can be scheduled to create a nightly backup of all the bindings and MSIs for all the applications in BizTalk. It uses the Powershell Extensions for BizTalk to enumerate the application names, then calls BTSTask once for the bindings, and once for the MSI.

It gives you the ability to customize your backup folder names and files names. For example, if your application name is “ABC.Orders”, the backups are:
ABC.Orders_2019_05_17__09_10_21.xml
ABC.Orders_2019_05_17__09_10_21.msi

You could make changes to create a new folder for each set of backups, example: Backups_2019_05_17__09_10_21.

Another enhancement could be to zip the archives, or to purge archives over x days.

There is one trick. You may also want to backup the Parties. I’m currently on BizTalk 2013, and I know there are some improvements for supporting importing/exporting parties individually in 2016. Given that I’m on BT2013, I decided to backup the parties just once. So if the application name = “BizTalk EDI Application”, I add the parameter for the party backup, and they will be in that file. You could also create a dummy empty application and use it.

<#

       Author: Neal Walters 
  Description: Backup BizTalk Applications (both Bindings and Application/MSIs) via Script 
         Date: May 2019 

#>

Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions
#This next line only needed when SQL server is not on same machine as BizTalk
New-PSDrive -Name BizTalk -Root BizTalk:\ -PsProvider BizTalk -Instance "YourSQLServer" -Database BizTalkMgmtDb

$exportFolder = "c:\Backup\BizTalk" 
$server = "YourSQLServer"
$database = "BizTalkMgmtDB"

cls

$apps = Get-ChildItem -Path "Biztalk:\Applications"

foreach ($app in $apps) 
    {
        Write-Host "===== Application: $($app.Name) ==== " 

        if ($app.Name -ne "BizTalk.System")   # avoid error trying to export this app 
          {
            $fmtDateTime = $(get-date -f yyyy_MM_dd__HH_mm_ss)
            $bindingsDestFilename = "${exportFolder}\$($app.Name)_$fmtDateTime.xml" 
            $msiAppDestFilename = "${exportFolder}\$($app.Name)_$fmtDateTime.msi" 
           
            write-host $bindingsDestFilename 
            $allArgs = @("ExportBindings", "/Destination:$bindingsDestFilename",  "/ApplicationName:$($app.Name)",
                "/Server:$server", "/Database:$database") 
            if ($app.Name -eq "BizTalk EDI Application") 
            {
               #just backup the parties one time with this one app 
               $allArgs += "/GlobalParties"
            }

            write-host "Args=$allArgs"
            & "c:\Program Files (x86)\Microsoft BizTalk Server 2013\BTSTask.exe" $allArgs

            $allArgs = @("ExportApp", "/Package:$msiAppDestFilename",  "/ApplicationName:$($app.Name)",
                "/Server:$server", "/Database:$database") 
            write-host "Args=$allArgs"
            & "c:\Program Files (x86)\Microsoft BizTalk Server 2013\BTSTask.exe" $allArgs
          }
    }

 

I’m writing a custom deploy solution for BizTalk. If the application doesn’t exist, I need to call “BTSTask AddApp” to add it.

Sample:


Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions

function checkApplicationExists ($appName) 
{
    cd "Biztalk:\Applications"
    $apps = Get-ChildItem
    $boolFoundMatch = $false 
    foreach ($app in $apps) 
      {
         Write-Host "  Testing $($app.Name) " 
         if ($app.Name -eq $appname) 
         {
            $boolFoundMatch = $true 
         }
      }
    return $boolFoundMatch 
  
}

cls
# Test an application that you know exists 
$appName = "Test.Vendors"
$app1Exists = checkApplicationExists $appname 
Write-Host "$appName $app1Exists" 

# Test an application that you know does not exist 
$appName = "Test.Vendors.NonExistent"
$app1Exists = checkApplicationExists $appname 
Write-Host "$appName $app1Exists" 


PowerShell extensions allow you to interact with BizTalk Artificacts. For example, you can like list applications, sendports, receive ports, host instances, and enable/disable them in PowerShell.

First run the InstallUtil

C:\Windows\system32>c:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe "c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Utilities\PowerShell\BizTalkFactory.PowerShell.Extensions.dll"

Output:
Microsoft (R) .NET Framework Installation utility Version 4.7.2558.0
Copyright (C) Microsoft Corporation. All rights reserved.

Running a transacted installation.

Beginning the Install phase of the installation.
See the contents of the log file for the c:\Program Files (x86)\Microsoft BizTal
k Server 2013\SDK\Utilities\PowerShell\BizTalkFactory.PowerShell.Extensions.dll
assembly’s progress.
The file is located at c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\
Utilities\PowerShell\BizTalkFactory.PowerShell.Extensions.InstallLog.
Installing assembly ‘c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Ut
ilities\PowerShell\BizTalkFactory.PowerShell.Extensions.dll’.
Affected parameters are:
logtoconsole =
assemblypath = c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Utili
ties\PowerShell\BizTalkFactory.PowerShell.Extensions.dll
logfile = c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Utilities\
PowerShell\BizTalkFactory.PowerShell.Extensions.InstallLog

The Install phase completed successfully, and the Commit phase is beginning.
See the contents of the log file for the c:\Program Files (x86)\Microsoft BizTal
k Server 2013\SDK\Utilities\PowerShell\BizTalkFactory.PowerShell.Extensions.dll
assembly’s progress.
The file is located at c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\
Utilities\PowerShell\BizTalkFactory.PowerShell.Extensions.InstallLog.
Committing assembly ‘c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Ut
ilities\PowerShell\BizTalkFactory.PowerShell.Extensions.dll’.
Affected parameters are:
logtoconsole =
assemblypath = c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Utili
ties\PowerShell\BizTalkFactory.PowerShell.Extensions.dll
logfile = c:\Program Files (x86)\Microsoft BizTalk Server 2013\SDK\Utilities\
PowerShell\BizTalkFactory.PowerShell.Extensions.InstallLog

The Commit phase completed successfully.

The transacted install has completed.

Next, in Powershell (assuming you have already set your execution policy):

If your SQL Server is on same machine as BizTalk this should work:

Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions

#Verify it works by listing the BizTalk Applications 
cd "Biztalk:\Applications\"
Get-ChildItem | ft -auto 

If you SQL Server is on a different machine than the BizTalk server, then add the New-PSDrive statement as below (StackOverflow)

Add-PSSnapIn -Name BiztalkFactory.PowerShell.Extensions
New-PSDrive -Name BizTalk -Root BizTalk:\ -PsProvider BizTalk -Instance MySqlServer -Database BizTalkMgmtDb

#Verify it works by listing the BizTalk Applications 
cd "Biztalk:\Applications\"
Get-ChildItem | ft -auto 

Every case is unique, but here’s what happened to me.

My goal was to receive a CSV file, and have it split into multiple output files in the Send Port. I did specify my CSV flat-file pipeline in my Receive Location’s Pipeline.

I took over a project at a new client. And while re-writing the code, I changed the names of all the programs and namespaces from XYZLongCompany, to just XYZ.

When I built the receive location on the test system, I copied the old long names, instead of the new short names into my Receive Location Pipeline properties, where you specify the “Document Spec Name” and the “Header Spec Name”.

This MSDN post shows how to find the document spec name by expanding the schemas then showing the properties. I can’t include any screen shots with actual client name.

I got this error from the following Scripting Functoid with inline C# script:

public int PutHL03()
{
     if (hl01 > 2) return "I"; 
     else if (hl01 == 1) return "S"; 
     return "0"; 
}
You can see it is returning string, but I specified the return type as “int”. Just changed “int” to “string” as the return type, and it worked. At least this error, pointed to “Inline Script”. See this StackOverflow question/answer I posted with a similar error, but there the I could have sworn the error was related to an XSLT sum, when it was really just a small error in a similar scripting functoid. https://stackoverflow.com/questions/55070442/biztalk-map-xslt-1-0-sum-cannot-implicitly-convert-type-string-to-int