Tuesday, February 26, 2013

Script BizTalk Application export to .msi with options using PowerShell

I've had the need to export BizTalk Applications using scripts, but with the requirement to not export web directories or global parties to the .msi file.

This can be done using the GUI:


However, it cannot be done (that I know of) using the btstask command with the exportapp parameter.

I opted for creating a PowerShell script that more or less extends the btstask exportapp command. The script takes a few parameters making it a bit more versatile:

$appName is the name of the BizTalk application to export
$exportPath is the path to write the .msi file to
$exportWebDir is a boolean indicating whether to also export web directories or not
$removeDefaultBinding is a boolean controlling whether the default bindings will be written to the .msi file or not. This is handy to remove in those cases you want to just keep bindings for dev/test/production environments.
$exportGlobalParties is a boolean controlling whether to include the Global Parties in the binding file or not. These will of course not be written if for instance you only have the default bindings and set the parameter $removeDefaultBinding to false and $exportGlobalParties to true, since the binding file never will be written at all.

The script basically dumps a ResourceSpecification file which then gets modified depending on the parameters entered. This ResourceSpecification is then used as input to the btstask exportapp command creating an .msi file according to our needs.

The full script looks like this:

param($appName, $exportPath, $exportWebDir, $removeDefaultBinding, $exportGlobalParties)

Write-Output "Exporting ResourceSpec..."
BTSTask ListApp /ApplicationName:$appName /ResourceSpec:$pwd\ResourceSpecTemp.xml

If (!($?))
{
    throw "Could not export resource specification. Verify application name."
}

Write-Output "Reading ResourceSpec..."
$xmlResource = [xml] (Get-Content $pwd\ResourceSpecTemp.xml)

If ($exportWebDir -eq $false)
{
    Write-Output "Removing web directories..."
    $delnodes = $xmlResource.SelectNodes("/*[local-name()='ResourceSpec' and namespace-uri()='http://schemas.microsoft.com/BizTalk/ApplicationDeployment/ResourceSpec/2004/12']/*[local-name()='Resources' and namespace-uri()='http://schemas.microsoft.com/BizTalk/ApplicationDeployment/ResourceSpec/2004/12']/*[local-name()='Resource' and namespace-uri()='http://schemas.microsoft.com/BizTalk/ApplicationDeployment/ResourceSpec/2004/12'][@Type='System.BizTalk:WebDirectory']")

    ForEach($delnode in $delnodes)
    {
        [void]$xmlResource.ResourceSpec.Resources.RemoveChild($delnode)
    }
}

If ($removeDefaultBinding -eq $true)
{
    Write-Output "Removing Default binding info..."
    $delnodes = $xmlResource.SelectNodes("/*[local-name()='ResourceSpec' and namespace-uri()='http://schemas.microsoft.com/BizTalk/ApplicationDeployment/ResourceSpec/2004/12']/*[local-name()='Resources' and namespace-uri()='http://schemas.microsoft.com/BizTalk/ApplicationDeployment/ResourceSpec/2004/12']/*[local-name()='Resource' and namespace-uri()='http://schemas.microsoft.com/BizTalk/ApplicationDeployment/ResourceSpec/2004/12'][@Type='System.BizTalk:BizTalkBinding'][@Luid='Application/$appName']")

    ForEach($delnode in $delnodes)
    {
        [void]$xmlResource.ResourceSpec.Resources.RemoveChild($delnode)
    }
}

Write-Output "Saving modified ResourceSpec..."
$xmlResource.Save("$pwd\ResourceSpecTemp.xml")

Write-Output "Exporting application $appName..."

If ($exportGlobalParties -eq $true)
{
    $globalPartiesParam = "/G"
}
else
{
    $globalPartiesParam = ""
}

BTSTask ExportApp /ApplicationName:$appName /Package:$exportPath\$appName.msi /ResourceSpec:$pwd\ResourceSpecTemp.xml $globalPartiesParam

If (!($?))
{
    throw "Could not export application. Verify application name and parameters."
}
       
Write-Output "Cleaning up..."
Remove-Item $pwd\ResourceSpecTemp.xml

Write-Output "DONE!"

Exit 0


And will be called like so:

ExportBtsMsi.ps1 BtsDemo1 "C:\" false false false

Which will result in output like this: