Install assemblies in Global Assembly Cache (GAC) with PowerShell

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

To finalize the export and deployment story from the previous blog post, given that we were working in a high-availability environment with multiple servers. And for those who are familiar with BizTalk Server, we need to:

This is a relatively simple task to perform; it’s simpler because it doesn’t require following a strict installation order and is faster compared to registering the assemblies in the product database. You could also use the previous PowerShell script on those machines, but it is a heavier process, so, for the reasons explained before, on the other machines where you just need to install the DLLs in the GAC, it will be better to use a lightweight script.

📝 One-Minute Brief

This is a PowerShell script that goes to a folder containing assemblies and install them in the Global Assembly Cache (GAC).

We could do it in a bulk process and GAC the assemblies for all applications in a single script, but I chose to do it in a controlled fashion.

Here is a sample of the script:

# Collect DLLs
$files = Get-ChildItem -LiteralPath $SourceFolder -Filter *.dll -File -Recurse:$Recurse
if (-not $files -or $files.Count -eq 0) {
    Write-Warning "No DLLs found in: $SourceFolder"
    return
}

$results = @()

# Detect edition (Desktop == Windows PowerShell/.NET Framework)
$onDesktop = ($PSVersionTable.PSEdition -eq 'Desktop' -or $PSVersionTable.PSVersion.Major -le 5)

# Try .NET Framework Publish API first when on Desktop
$publisher = $null
if ($onDesktop) {
    try {
        [void][Reflection.Assembly]::Load("System.EnterpriseServices")
        $publisher = New-Object System.EnterpriseServices.Internal.Publish
    } catch {
        Write-Warning "Could not create System.EnterpriseServices.Internal.Publish in this session. Will try gacutil.exe."
    }
}

if ($publisher) {
    foreach ($f in $files) {
        try {
            $publisher.GacInstall($f.FullName)
            $results += [pscustomobject]@{ File=$f.FullName; Method="Publish.GacInstall"; Result="GACed" }
            Write-Host "GACed: $($f.Name)" -ForegroundColor Green
        } catch {
            $results += [pscustomobject]@{ File=$f.FullName; Method="Publish.GacInstall"; Result="ERROR: $($_.Exception.Message)" }
            Write-Warning "Failed: $($f.Name) -> $($_.Exception.Message)"
        }
    }
    "`n===== SUMMARY ====="; $results | Format-Table -AutoSize
    return
}

# Fallback: locate gacutil.exe
$gacutil = $null
$probeRoots = @(
  'C:\Program Files (x86)\Microsoft SDKs\Windows',
  'C:\Program Files (x86)\Microsoft Visual Studio',
  'C:\Program Files\Microsoft SDKs\Windows'
)

foreach ($root in $probeRoots) {
    if (Test-Path $root) {
        $found = Get-ChildItem -Path $root -Filter gacutil.exe -Recurse -ErrorAction SilentlyContinue |
                 Sort-Object FullName -Unique |
                 Select-Object -First 1 -ExpandProperty FullName
        if ($found) { $gacutil = $found; break }
    }
}

if (-not $gacutil) {
    throw @"
No valid GAC installer found:
 - System.EnterpriseServices.Internal.Publish unavailable (likely PowerShell 7+ or missing .NET Framework)
 - gacutil.exe not found in common SDK/VS locations

Fixes:
 - Run in **Windows PowerShell 5.1** (x64) as Administrator; or
 - Install Windows SDK / VS Build Tools to get **gacutil.exe**.
"@
}

Write-Host "Using gacutil: $gacutil" -ForegroundColor Cyan

foreach ($f in $files) {
    try {
        # Use Start-Process; do NOT pipe a null path (pre-validated above)
        $p = Start-Process -FilePath $gacutil -ArgumentList @('/if', $f.FullName) -NoNewWindow -Wait -PassThru
        if ($p.ExitCode -eq 0) {
            $results += [pscustomobject]@{ File=$f.FullName; Method="gacutil /if"; Result="GACed" }
            Write-Host "GACed: $($f.Name)" -ForegroundColor Green
        } else {
            $results += [pscustomobject]@{ File=$f.FullName; Method="gacutil /if"; Result="ERROR: ExitCode $($p.ExitCode)" }
            Write-Warning "Failed: $($f.Name) -> ExitCode $($p.ExitCode)"
        }
    } catch {
        $results += [pscustomobject]@{ File=$f.FullName; Method="gacutil /if"; Result="ERROR: $($_.Exception.Message)" }
        Write-Warning "Failed: $($f.Name) -> $($_.Exception.Message)"
    }
}

With this, all assemblies will be installed in the GAC within a few minutes.

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