Following the nightmare exportation story in the previous blog post, I decided to create the final solution that combines a bit of the logic from the last script with a simplified XML and some manual work, with the help of ChatGPT.
📝 One-Minute Brief
This is a PowerShell script that goes to an XML File with a list of all assemblies of a specific BizTalk application and copies the DLL from the GAC to a local folder per application.
The logic was:
- I manually copied the resource list from the BizTalk Server Administration Console by selecting all the lines and CTRL-C

- And past it (CTRL-V) to different sheets inside an Excel file – each sheet is an application, and each sheet contains the list of resources for that application. Optionally, you can delete the unnecessary columns

- Then I ask ChatGPT to convert this Excel in a simple XML file with this format:
<?xml version='1.0' encoding='utf-8'?>
<Applications>
<Application name="Target">
<Assembly>Target.Common.Messaging</Assembly>
<Assembly>Target.Common.Processing</Assembly>
<Assembly>Target.TargetPublishNURCT.Messaging</Assembly>
<Assembly>Target.TargetPublishNURCT.Staging</Assembly>
<Assembly>Target.TargetPublishODS.Messaging</Assembly>
<Assembly>Target.TargetPublishODS.Processing</Assembly>
<Assembly>Target.TargetPublishODS.Staging</Assembly>
<Assembly>Target.TargetReceiveInfoware.messaging</Assembly>
<Assembly>Target.TargetReceiveInfoware.Processing</Assembly>
<Assembly>Target.TargetReceiveInfoware.Staging</Assembly>
<Assembly>Name</Assembly>
</Application>
<Application name="Sales">
<Assembly>...</Assembly>
<Assembly>Name</Assembly>
</Application>
...
</Applications>
This is a simple, clean XML file containing a list of all assemblies for each application. Now, the last step was to create a PowerShell script that goes to that XML and:
- Per application, creates a local folder
- And copies from the Global Assembly Cache (GAC) the list of assemblies (DLL) to that local folder
Here is a sample of the script:
# Iterate Applications
$apps = $xml.SelectNodes('/Applications/Application')
if (-not $apps -or $apps.Count -eq 0) {
throw "No <Application> nodes found in XML: $XmlPath"
}
foreach ($app in $apps) {
$appName = [string]$app.GetAttribute('name')
if ([string]::IsNullOrWhiteSpace($appName)) { continue }
# Sanitize folder name (Windows forbids these chars)
$safeApp = ($appName -replace '[\\/:*?"<>|]', '_').Trim()
$appFolder = Join-Path $ExportRoot $safeApp
if (-not (Test-Path -LiteralPath $appFolder)) {
New-Item -ItemType Directory -Path $appFolder | Out-Null
}
Write-Host "`n== Application: $appName ==" -ForegroundColor Cyan
# Assemblies for this application
$asmNodes = $app.SelectNodes('./Assembly')
if (-not $asmNodes -or $asmNodes.Count -eq 0) {
Write-Warning "No <Assembly> items for application '$appName'."
continue
}
foreach ($node in $asmNodes) {
$asmName = [string]$node.InnerText
if ([string]::IsNullOrWhiteSpace($asmName)) { continue }
$dllPath = $null
$hitsAll = @()
foreach ($bucket in $gacBuckets) {
$nameDir = Join-Path (Join-Path $gacRoot $bucket) $asmName
if (-not (Test-Path -LiteralPath $nameDir)) { continue }
# Gather any <asmName>.dll under version folders
$hits = @(Get-ChildItem -LiteralPath $nameDir -Recurse -Filter ("{0}.dll" -f $asmName) -ErrorAction SilentlyContinue)
if ($hits.Count -gt 0) {
$hitsAll += $hits
}
}
if ($hitsAll.Count -eq 0) {
Write-Warning "GAC dll not found for '$asmName'."
$summary += [pscustomobject]@{ Application=$appName; Assembly=$asmName; Source=''; Dest=''; Result='NotFound' }
continue
}
# Prefer highest version by parsing parent folder name "<version>__<pkt>"
$best = $hitsAll |
Sort-Object -Descending -Property @{
Expression = {
# Try to extract version from parent dir name
$parent = Split-Path $_.DirectoryName -Leaf
$ver = $null
if ($parent -match $verFolderPattern) {
try { [version]$matches['ver'] } catch { [version]'0.0.0.0' }
} else { [version]'0.0.0.0' }
}
} |
Select-Object -First 1
$dllPath = $best.FullName
try {
$dest = Join-Path $appFolder ("{0}.dll" -f $asmName)
Copy-Item -LiteralPath $dllPath -Destination $dest -Force:$Overwrite
Write-Host ("Copied: {0} -> {1}" -f $asmName, $dest) -ForegroundColor Green
$summary += [pscustomobject]@{ Application=$appName; Assembly=$asmName; Source=$dllPath; Dest=$dest; Result='Copied' }
}
catch {
Write-Warning ("Failed to copy {0}: {1}" -f $asmName, $_.Exception.Message)
$summary += [pscustomobject]@{ Application=$appName; Assembly=$asmName; Source=$dllPath; Dest=''; Result="Error: $($_.Exception.Message)" }
}
}
}
This was able to solve all my problems. Unfortunately, I had to perform some manual tasks, but in a few minutes, I had all the necessary DLLs (assemblies) to import and install in another environment – we will see that in another blog post.
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!