How to Export BizTalk Applications assemblies (resources) from the GAC to a local folder with PowerShell

  • Sandro Pereira
  • Nov 18, 2025
  • 4 min read

Following the last blog post – How to Export BizTalk Applications resources to an XML file with PowerShell – and because that previous approach didn’t work for me, because, either failed to export, gave a timeout, or simply got stuck trying to accomplish this resource exportation. I then decide to use a different strategy.

📝 One-Minute Brief

This is a PowerShell script that goes to the BizTalkMgmtDb database in order to export a list of all assemblies of a specific BizTalk application and copies the DLL from the GAC to a local folder.

But this time, do it in style! The goal was:

  • Based on the application name, access the internal databases of BizTalk Server and get a list of all resources belonging to that application
  • Then, based on the list provided from BizTalk Server databases, go to the GAC and get a copy of the DLLs into a folder

Here is a sample of the PowerShell script:

# Run the SQL (returns XML) using .NET client
$cn = New-Object System.Data.SqlClient.SqlConnection
$cn.ConnectionString = "Server=$SqlServer;Database=$DbName;Trusted_Connection=True;MultipleActiveResultSets=False;"
$cn.Open()

# Your SQL (parametrized). It returns XML with <Assemblies><Assemby><nvcName>...</nvcName>...</Assemblies>
$q = @"
SELECT [nvcName]
FROM [dbo].[bts_assembly]
WHERE nApplicationID LIKE (
    SELECT [nID]
    FROM [dbo].[bts_application]
    WHERE nvcName LIKE @app
)
FOR XML PATH('Assemby'), ROOT('Assemblies');
"@

$cmd = $cn.CreateCommand()
$cmd.CommandText = $q
$null = $cmd.Parameters.Add("@app",[System.Data.SqlDbType]::NVarChar,256)
$cmd.Parameters["@app"].Value = $AppName

# Use ExecuteXmlReader to get the XML cleanly
$xmlReader = $cmd.ExecuteXmlReader()

# Load into [xml]
$xml = New-Object System.Xml.XmlDocument
$xml.Load($xmlReader)

$xmlReader.Close()
$cn.Close()

# Extract assembly simple names (from <Assemby><nvcName>...)
$asmNames = @()
$nodes = $xml.SelectNodes("//Assemblies/Assemby/nvcName")
foreach ($n in $nodes) {
    $val = [string]$n.InnerText
    if ([string]::IsNullOrWhiteSpace($val)) { continue }
    # In BizTalk, nvcName is the simple assembly name (no version/PKT). Keep as-is.
    $asmNames += $val.Trim()
}

if (-not $asmNames -or $asmNames.Count -eq 0) {
    Write-Warning "No assemblies found in SQL for application LIKE '$AppName'."
    exit 1
}

# Locate each DLL in the GAC and copy it
$gacRoot    = Join-Path $env:WINDIR 'Microsoft.NET\assembly'
$gacBuckets = @('GAC_MSIL','GAC_32','GAC_64')
$report = @()
$errors = @()

foreach ($name in $asmNames | Select-Object -Unique) {
    $dllPath = $null

    foreach ($bucket in $gacBuckets) {
        $nameDir = Join-Path (Join-Path $gacRoot $bucket) $name
        if (-not (Test-Path -LiteralPath $nameDir)) { continue }

        # Search for <Name>.dll under the assembly folder; we don't know version/PKT from this query
        $hits = @(Get-ChildItem -LiteralPath $nameDir -Recurse -Filter ("{0}.dll" -f $name) -ErrorAction SilentlyContinue)
        if ($hits.Count -gt 0) {
            # If multiple versions exist, pick the newest folder by LastWriteTime
            $dllPath = ($hits | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
            break
        }
    }

    if (-not $dllPath) {
        $msg = "GAC path not found for $name."
        Write-Warning $msg
        $errors += $msg
        continue
    }

    try {
        $dest = Join-Path $DestinationFolder ("{0}.dll" -f $name)
        Copy-Item -LiteralPath $dllPath -Destination $dest -Force:$Overwrite
        $report += [pscustomobject]@{
            AssemblyName  = $name
            SourceGacPath = $dllPath
            CopiedTo      = $dest
            Result        = 'Copied'
        }
        Write-Host "Copied: $name  ->  $dest" -ForegroundColor Green
    }
    catch {
        $msg = "Failed to copy $name from '$dllPath' -> '$DestinationFolder'. Error: $($_.Exception.Message)"
        Write-Warning $msg
        $errors += $msg
        $report += [pscustomobject]@{
            AssemblyName  = $name
            SourceGacPath = $dllPath
            CopiedTo      = $null
            Result        = 'Error'
        }
    }
}

And it will work… at least 90%!

The problem is that I cannot, at least yet, find a way to find the assembly’s helper classes. For example, the application below has two BizTalk Assemblies and a .NET assembly. The script can get the BizTalk Server Assemblies, but it cannot find them in the database, the .NET assembly, which, for me, is a no-go.

Nevertheless, this is a good resource.

Download

THIS POWERSHELL SCRIPT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND.

You can download the PowerShell Script used from GitHub here:

Hope you find this helpful! If you enjoyed the content or found it useful, and wish to support our efforts to create more, you can contribute to purchasing a Star Wars Lego set for my son!

Author: Sandro Pereira

Sandro Pereira lives in Portugal and works as a consultant at DevScope. In the past years, he has been working on implementing Integration scenarios both on-premises and cloud for various clients, each with different scenarios from a technical point of view, size, and criticality, using Microsoft Azure, Microsoft BizTalk Server and different technologies like AS2, EDI, RosettaNet, SAP, TIBCO etc. He is a regular blogger, international speaker, and technical reviewer of several BizTalk books all focused on Integration. He is also the author of the book “BizTalk Mapping Patterns & Best Practices”. He has been awarded MVP since 2011 for his contributions to the integration community.

Leave a Reply

Your email address will not be published. Required fields are marked *

The Ultimate Cloud
Management Platform for Azure

Supercharge your Azure Cost Saving

Learn More
Turbo360 Widget

Back to Top