A Go port of PSAppDeployToolkit (PSADT) v4 — a toolkit for building Windows application deployments. It provides deployment session management, CMTrace logging, localized user dialogs, deferral logic, MSI helpers and a broad set of Windows system utilities, as an importable Go SDK plus a CLI runner.
Windows-only at runtime. The toolkit targets
GOOS=windows(amd64/arm64). It cross-compiles and unit-tests its portable logic on any platform; the syscall layers only execute on Windows.
Every exported function is a 1:1 port of the PSADT PowerShell function of the same name with the hyphens removed, so existing deployment scripts translate mechanically:
| PowerShell (PSADT) | Go (winadt) |
|---|---|
Open-ADTSession |
winadt.OpenADTSession |
Start-ADTMsiProcess |
winwinadt.StartADTMsiProcess |
Show-ADTInstallationWelcome |
winwinadt.ShowADTInstallationWelcome |
Copy-ADTFile |
winadt.CopyADTFile |
Set-ADTRegistryKey |
winadt.SetADTRegistryKey |
PowerShell-runtime plumbing (Initialize-ADTFunction, New-ADTErrorRecord, …)
has no Go counterpart; the *-ADTModuleCallback family is replaced by
SessionHooks, and New-ADTTemplate is provided by adt new.
A deployment is a small Go program describing its phases — the analogue of
PSADT's Invoke-AppDeployToolkit.ps1:
package main
import (
"context"
"github.com/deploymenttheory/go-appdeploymenttoolkit/winadt"
)
func main() {
(&winadt.Deployment{
Session: winadt.SessionOptions{
AppVendor: "VideoLAN",
AppName: "VLC media player",
AppVersion: "3.0.23",
AppProcessesToClose: []winadt.ProcessObject{{Name: "vlc", Description: "VLC media player"}},
},
PreInstall: func(ctx context.Context, s *winadt.DeploymentSession) error {
_, err := winadt.ShowADTInstallationWelcome(ctx, winwinadt.ShowADTInstallationWelcomeOptions{
CloseProcesses: s.Options().AppProcessesToClose, AllowDefer: true, DeferTimes: 3,
})
return err
},
Install: func(ctx context.Context, s *winadt.DeploymentSession) error {
_, err := winadt.StartADTMsiProcess(ctx, winwinadt.StartADTMsiProcessOptions{
Action: "Install", Path: "vlc.msi",
})
return err
},
}).Run(context.Background())
}Build it for Windows and run it with the standard PSADT frontend flags:
GOOS=windows go build -o Invoke-AppDeployToolkit.exe
Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode InteractiveDeployments can be defined as data instead of code: a deployment.yaml at the
package root composes steps from a typed catalog and is validated and executed
by the adt binary — locally or in a pipeline (validation is fully portable,
so CI can gate manifests without a Windows runner):
apiVersion: v0.1.0-alpha
kind: Deployment
session:
appVendor: Contoso
appName: Widget
appVersion: "1.2.3"
closeProcesses: [{name: widget}]
phases:
preInstall:
- uses: dialog.welcome
with: {allowDefer: true, deferTimes: 3, promptToSave: true}
install:
- uses: msi.install
with: {path: Widget.msi, transforms: [Widget.mst]}
postInstall:
- uses: registry.set
with: {key: 'HKLM:\SOFTWARE\Contoso\Widget', name: Installed, value: 1, type: dword}adt validate <package-dir>— layered validation (strict schema with did-you-mean suggestions, cross-field semantics,Files/existence,--targetplatform support) with gcc-style positions and--jsonoutput.adt steps— the step catalog (--jsonfor tooling).adt schema— the format's JSON Schema (draft 2020-12), generated from the registry and checked in asmanifest/winadt.schema-v0.1.0-alpha.json(semver-versioned artifact); emit it beside a package and reference it with ayaml-language-servermodeline for editor autocomplete.- The
manifestpackage exposes the schema, catalog, validator and compiler programmatically.
The adt command is the analogue of Invoke-AppDeployToolkit.exe:
adt run <package-dir>— run a deployment package: adeployment.yamlmanifest when present, else the zero-config MSI flow (single MSI underFiles/, with MST/MSP auto-discovery) with no author code.adt validate <package-dir>/adt steps— manifest validation and the step catalog (see above).adt new <dir> --name MyApp— scaffold a package (Files/,SupportFiles/,Config/,Strings/,Assets/, a starterdeployment.yaml, ago.modand a deploymentmain.go).
go install github.com/deploymenttheory/go-appdeploymenttoolkit/cmd/adt@latest
adt validate ./MyPackage
adt run ./MyPackage --deployment-type Install --deploy-mode Silent- Package config lives in
Config/config.yaml, mirroring PSADT'sconfig.psd1section structure (Assets, MSI, Toolkit, UI); embedded defaults are used when it is absent. - String tables ship for all 26 PSADT cultures plus English; override via
Strings/strings.yaml.
Interactive dialogs render through Microsoft Edge WebView2 (via the CGo-free
jchv/go-webview2), with a native MessageBox/TaskDialog fallback when the
WebView2 runtime is absent. Deployments running as SYSTEM show dialogs in the
interactive user session via a same-binary client re-exec over anonymous pipes.
deploy/ shared platform-neutral engine (sessions, phases, hooks, exit codes)
winadt/ Windows SDK — all ~170 PSADT-ported functions
macadt/ macOS SDK (proof-of-life; domain catalog is future work)
manifest/ YAML workflow layer: step catalog, validator, compiler, schemas
internal/shared/ engine internals (session, logging, config, strings, ipc, ...)
internal/win/ Windows domain internals (msi, registry, wts, dialogs, ...)
cmd/adt/ CLI (run / validate / steps / schema / new / client)
examples/ runnable deployment programs
tools/ the psd1→YAML converter for config and string tables
All five porting phases are complete: core session engine, system domains
(registry, filesystem, INI, process, MSI, services, shortcuts, users), UI and
cross-session client-server, CLI runner, and the long tail. See
docs/windows-smoke.md for the manual Windows
verification checklist (the syscall layers are cross-compiled and linted here
but only execute on Windows).
go-bindings-win32— generated Win32 API bindings (MSI, WTS, registry, shell, tasks, …).go-bindings-wmi— typed WMI runtime (ConfigMgrTriggerSchedule,Win32_QuickFixEngineering).
See LICENSE.