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 task is relatively simple. More importantly, it does not require a strict installation order. As a result, it runs faster than registering assemblies in the product database.

You could reuse the previous PowerShell script on these machines. However, that approach is heavier. Therefore, on servers where you only need to install DLLs in the Global Assembly Cache (GAC), using a lightweight script is a better option.

📝 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!

Buy me a coffee
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