PowerPacker is a framework designed to let AI Agents (Gemini CLI, Claude Code, Cursor) autonomously build, validate, and test PowerShell App Deployment Toolkit (PSADT) v4 packages.
The Human provides the Intent; the Agent provides the Engine.
- Install an AI Agent: Ensure you have a tool like Gemini CLI installed.
- WinGet Integration: Configure your Agent to use the WinGet MCP server (see
.vscode/mcp.json.example). - Environment: Ensure
gh(GitHub CLI) is authenticated so the Agent can download the PSADT template. - Module (local packing): From the repository root,
Import-Module .\PowerPacker.psd1to useNew-PowerPackerPackagein PowerShell.
Create a simple Markdown file in the Definitions/ folder. This is your primary manual task. You can use any of the following standard PSADT v4 sections:
# Pre-Install/# Post-Install# Install# Pre-Uninstall/# Post-Uninstall# Uninstall# Detection
YAML frontmatter must include at least winget_id (and typically name). Optional keys such as version are parsed and echoed under Package in artifact-metadata.json; pinning a WinGet version for downloads uses New-PowerPackerPackage -WingetVersion, not frontmatter version automatically.
Definitions may set architecture in YAML frontmatter (auto, native, x64, x86, or arm64). Omitted values default to auto, which probes WinGet for x64, arm64, x86, and neutral, downloads each distinct installer URL it finds, and records per-architecture provenance in artifact-metadata.json (MetadataSchemaVersion 2): InstallerFilesByArchitecture (paths under the artifact) and InstallerMetadataByArchitecture (per-architecture installer URL, SHA256, type, resolved version, and requested scope when supplied). native uses the same discovery rules as auto but records a different ArchitecturePolicy label when you want metadata to express a native-first posture. Locked values download exactly one architecture.
For more detail on endpoint behavior and deploy-script patterns, see PLAN-ARM-ARCHITECTURE.md.
Runtime fallback matrix (deploy scripts)
ARM64 endpoints: ARM64 → X64 → NEUTRAL → fail.
X64 endpoints: X64 → NEUTRAL → fail.
X86 endpoints: X86 → NEUTRAL → fail (do not fall back to X64).
New-PowerPackerPackage -Architecture overrides the definition when you need a one-off build (for example, forcing x64 on a definition that normally uses auto).
For New-PowerPackerPackage, WinGet metadata and download scope are controlled by the -Scope parameter (machine or user). If you omit -Scope, WinGet is invoked without an explicit scope flag.
You may still document intent in definition YAML (for example scope: machine), but that YAML is not read by the cmdlet today; use -Scope for consistent winget show / winget download behavior and matching rows in artifact-metadata.json.
- Machine scope (
-Scope machine): Aligns with installers that land underProgram Fileswhen the manifest supports it. Recommended default for enterprise deployment when the package supports it. - User scope (
-Scope user): Aligns with per-user installers under%LOCALAPPDATA%. Use when the definition explicitly calls for per-user deployment.
Omaha Application Warning: Google Omaha-based apps (Brave, Chrome, Edge) are highly sensitive to scope. If you request a user-scope install but run it as an Administrator, the installation will likely fail with error 0x80040c01. The Agent is instructed to prefer Standalone machine-wide installers for these apps to ensure reliable deployment.
Example: Definitions/mozilla.firefox.md
---
winget_id: Mozilla.Firefox
name: Mozilla Firefox
version: 124.0.2
---
## Install
Install Firefox using the silent installer.
## Uninstall
Uninstall Firefox using the helper.exe in the installation directory or the product code.
## Detection
Check for the existence of `C:\Program Files\Mozilla Firefox\firefox.exe`.When defining the uninstall process, provide clear instructions for the Agent:
- Silent Uninstall: Specify if the uninstall should run silently (e.g., "Uninstall using silent arguments")
- Custom Actions: Note any pre-uninstall tasks (close applications, stop services) or post-uninstall cleanup
- Registry Fallback: If the ProductCode is unknown, mention that a registry lookup should be used to find the uninstall string
Example: Definitions/microsoft.visualstudiocode.md (uninstall and registry-oriented guidance)
---
winget_id: Microsoft.VisualStudioCode
name: Microsoft Visual Studio Code
---
## Detection
Check for the machine-wide uninstall entry for `Microsoft Visual Studio Code` in the registry.
## Uninstall
Uninstall Visual Studio Code using the uninstall command from the registry with silent arguments. Prefer the machine-wide uninstall entry and fall back to the uninstaller in the application directory if the registry entry is unavailable.Tell the agent to pack the application. It will handle metadata lookup, script generation, AST validation, and artifact assembly.
Prompt: "Pack 7zip.7zip based on the definition."
Prompt: "Pack VSCodium fromDefinitions/vscodium.vscodium.mdusing the deploy script underExamples/DeployScripts/."
You can assemble an artifact without an agent by calling New-PowerPackerPackage with a definition Markdown file and a PSADT entry script (often copied or adapted from Examples/DeployScripts/).
Import-Module .\PowerPacker.psd1 -Force
New-PowerPackerPackage `
-DefinitionPath .\Definitions\vscodium.vscodium.md `
-DeployScriptPath .\Examples\DeployScripts\multi-arch.installer.example.ps1 `
-Scope machine `
-ForceUseful parameters (see Public/New-PowerPackerPackage.ps1):
| Parameter | Purpose |
|---|---|
-DefinitionPath / -DeployScriptPath |
Required inputs. |
-OutputDirectory |
Where to create the artifact folder (default: Artifacts under the module). |
-PackageDirectoryName |
Override the default folder name derived from winget_id. |
-EntryScriptName |
PSADT entry script name in the artifact (default: Invoke-AppDeployToolkit.ps1). |
-PsadtTemplateZipPath |
Use a local PSADT v4 template zip instead of downloading via gh. |
-WingetVersion / -WingetSource |
Pin WinGet version or source. |
-Architecture |
Override definition frontmatter (auto, native, x64, x86, arm64). |
-InstallerType / -Locale |
Passed through to WinGet resolution and download. |
-Scope |
machine or user for WinGet show/download consistency. |
-SkipInstallerDownload |
Expand template and write metadata without downloading installers (offline or layout checks). |
-Force |
Overwrite an existing artifact directory for the same package name. |
The default artifact directory name is the winget_id with characters that are invalid in folder names replaced by - (for example VSCodium.VSCodium → Artifacts\VSCodium.VSCodium).
Once packing finishes, the artifact lives under Artifacts/<PackageFolder>/. Test the package by running the standard PSADT entry script from that directory:
cd .\Artifacts\VSCodium.VSCodium
# Run Install
.\Invoke-AppDeployToolkit.ps1 -DeploymentType Install -DeployMode Interactive
# Run Uninstall
.\Invoke-AppDeployToolkit.ps1 -DeploymentType Uninstall -DeployMode Interactiveartifact-metadata.json (schema v2) under SupportFiles\PowerPacker\ includes, among others: MetadataSchemaVersion, ArchitecturePolicy, AvailableArchitectures, InstallerFilesByArchitecture, InstallerMetadataByArchitecture, a summary Installer block (legacy “primary” installer view), Package (parsed definition frontmatter and sections), and PSADT template provenance.
Tip: Since artifacts are standard PSADT v4 packages, you can use all standard PSADT parameters like
-DeployMode Silent,-DeployMode Interactive, or-AllowRebootPassThru.
- Keep WinGet scope consistent: If the package is intended for machine deployment, use the same scope for both metadata lookup and installer download (for the cmdlet,
-Scope machine; for manual debugging, the same flag onwinget showandwinget download). Queryingwinget showwithout--scope machineand then downloading with--scope machinecan produce mismatched metadata inartifact-metadata.json. - Multi-architecture builds verify SHA256: When installers are downloaded, PowerPacker hashes each payload and fails the build if it does not match the WinGet metadata SHA256 for that architecture.
- Per-architecture WinGet logs: Multi-architecture builds save
winget-show-<arch>.txtandwinget-download-<arch>.txtunderSupportFiles\PowerPacker\instead of a single pair of files. - Verify artifact metadata against the downloaded installer: After packaging, compare the installer filename in
Files/, the saved WinGet manifest, andSupportFiles\PowerPacker\artifact-metadata.json. The URL, SHA256, and scope should all describe the same installer variant. - AST validation (
Test-PSADTAst): The validator expectsOpen-ADTSession, then a top-leveltry/catchwrapping main logic before the statement that containsClose-ADTSession. Scripts that only callClose-ADTSessioninsidefinallycan fail that layout rule. Scripts that readInstallerFilesByArchitecturemust use[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture, aswitchmapping, andWrite-ADTLogEntryfor selection and fallbacks. - Do not treat
Build/as a source-of-truth folder: Reusable deploy scripts should live in a tracked folder, not an ignored scratch directory. This repo usesExamples\DeployScripts\for committed reference scripts (see Examples/DeployScripts/README.md). Canonical multi-arch selection:multi-arch.installer.example.ps1; app-specific examples includemicrosoft.visualstudiocode.ps1andslacktechnologies.slack.ps1.
Definitions/: Human-written application requirements.Artifacts/: Generated, ready-to-run PSADT packages (default output ofNew-PowerPackerPackage).Examples/DeployScripts/: Tracked reference deploy scripts worth reusing or adapting (README).Tests/: Pester tests; runInvoke-Pester .\Tests\from the repository root after installing the Pester module.AGENTS.md: The rulebook you must feed to your AI Agent.Private/: Internal tools (AST validators, parsers, WinGet helpers) used by the module and Agent.Public/: Core cmdlets likeNew-PowerPackerPackage.