SCCM / ConfigMgr

PSADT 4 Application Deployment in ConfigMgr

From PSADT 4 package to ConfigMgr Application — folder layout, deployment types, detection methods, install and uninstall commands, user experience settings, and log-driven verification. Focused on the ConfigMgr integration.

SCCM ConfigMgr PSADT Application Deployment Packaging Detection Methods Enterprise
2026-04-20 · Miloch · 19 min read

The PowerShell App Deployment Toolkit — PSADT — is the de facto standard for wrapping Windows application installers in enterprise environments. It provides a reliable pattern for pre-install checks, user notification, process handling, the actual installation call, and post-install verification, all wrapped in a scriptable framework that plays well with the deployment engines that consume it. Configuration Manager is the most common such engine, and ConfigMgr's Application model and PSADT's wrapper pattern are a natural fit.

Version 4 of PSADT introduced a module-based architecture that departs significantly from the dot-sourced layout of version 3. Function names were systematically renamed with an ADT prefix, configuration moved from XML to PowerShell data files, and the package layout was tightened. For ConfigMgr integrators, the practical consequences are narrow but important: the entry-point command that the ConfigMgr Application calls is different from version 3, and the logging paths changed.

The following article focuses on the ConfigMgr side of the equation — how a PSADT 4 package becomes a well-behaved ConfigMgr Application, which detection methods hold up in practice, which user experience settings matter, and how to read the relevant logs when something misbehaves. The internals of PSADT itself — writing the wrapper, handling dialogs, localisation — are covered in the PSADT documentation and are deliberately not duplicated here.

Why PSADT in the First Place

Bare vendor installers vary wildly in quality. Some accept silent parameters cleanly; others embed MSI payloads in outer bootstrappers that reject /quiet. Some exit with meaningful codes; others always return zero. Some check for running processes; others happily overwrite in-use binaries. Some localise their own user prompts; most do not.

A deployment toolkit solves these problems uniformly. PSADT wraps the vendor installer with:

For a ConfigMgr Administrator, this translates into higher success rates, clearer failure reporting, and a uniform user experience across the application catalogue.

PSADT 4 in One Page

PSADT 4 is a PowerShell module rather than a dot-sourced script library. The functions live in PSAppDeployToolkit, which is loaded at the start of the wrapper script. All exported functions carry the ADT prefix — Show-ADTInstallationWelcome, Start-ADTProcess, Write-ADTLogEntry, and so on — which eliminates the naming collisions that could arise when PSADT was sourced into a session with other modules loaded.

The package layout that a packager hands off to ConfigMgr contains, at a minimum:

The specific filenames and folder names are documented in the official PSADT repository and should be taken as authoritative. The ConfigMgr-facing surface — what matters for deployment — is the entry-point executable that the Application's install and uninstall commands call, and the log location PSADT writes to during execution.

Note
Packages originally built against PSADT 3 still work when PSADT 4 is installed in backward-compatible mode. For new packaging work, starting on version 4 avoids a later migration.

From Package to Application

A finalised PSADT 4 package is a folder tree on a packaging share — typically \\packaging\Packages\<Vendor>\<Product>\<Version>\. This folder is the content source for the ConfigMgr Application.

Creating the Application

In the ConfigMgr console, under Software Library → Application Management → Applications, Create Application launches the wizard. Two paths exist:

The metadata that matters later for reporting and user visibility:

For enterprise environments, a naming convention that surfaces vendor, product, and version in the Name field (for example, 7-Zip 24.09 x64) is strongly advised. The same string should appear in detection methods where applicable.

Adding a Deployment Type

An Application is a logical wrapper. The actual install and uninstall commands live in one or more Deployment Types. For PSADT packages, the type is Script Installer.

Deployment Types → Add → Script Installer launches a sub-wizard. The relevant settings:

Content tab

Programs tab

This is where the PSADT entry point is wired up. Install and uninstall commands call the PSADT wrapper with a deployment mode parameter:

text
Install program:
  Invoke-AppDeployToolkit.exe -DeploymentType Install -DeployMode Interactive

Uninstall program:
  Invoke-AppDeployToolkit.exe -DeploymentType Uninstall -DeployMode Silent

Repair program (optional):
  Invoke-AppDeployToolkit.exe -DeploymentType Repair -DeployMode Silent

The executable entry point, rather than the .ps1 wrapper, is called directly. This ensures elevation, PowerShell execution policy bypass, and signing of the entry point itself — all handled inside the toolkit.

Deploy mode values are interpreted by PSADT:

Detection Method tab

Detection is the single most important correctness element in a ConfigMgr Application. It is what ConfigMgr uses to determine whether the application is already installed, whether the last install succeeded, and whether a subsequent enforcement cycle needs to run. A broken detection method is the root cause of most phantom "install failed" statuses.

Four detection primitives are supported, combined by AND/OR:

Reliable detection patterns for PSADT-wrapped packages in the real world:

Warning
Custom detection scripts must return a non-empty standard output to signal detected. An empty stdout means not detected, regardless of the exit code. The custom script must also return an exit code of zero; a non-zero exit code is treated as a failure of the detection itself.

A minimal custom detection script:

powershell
# Detection: application present if the expected version is recorded in the registry
$key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{PRODUCT-GUID}"
$expected = "24.09"

if (Test-Path $key) {
    $installed = (Get-ItemProperty -Path $key).DisplayVersion
    if ($installed -eq $expected) {
        Write-Output "Installed"   # non-empty stdout = detected
        exit 0
    }
}
# Fall through: no output, application not detected
exit 0

User Experience tab

This is where the semantics of interactive versus session-zero are tuned:

Requirements tab

Optional conditions that must evaluate true before the install runs. Common requirements:

Requirements are evaluated on the client; a requirement that fails silently suppresses the install with a specific status in reporting.

Dependencies tab

Used when the application needs another application installed first. Dependencies are enforced automatically — installing the dependent application triggers the dependency install before the wrapper runs. For PSADT packages that depend on, say, a Visual C++ Redistributable, the redistributable is packaged as a separate Application and referenced here.

Content Distribution

Once the Application and Deployment Type are defined, content must be distributed to every DP that will serve the install.

Distribute Content launches a wizard that lists referenced content (the deployment type's source folder) and lets the DP or DP Group be chosen. For a lab with a single DP, the choice is trivial; in production, content is typically distributed to a DP Group that matches the collection's boundary group.

Monitoring the distribution lives under Monitoring → Distribution Status → Content Status. A distribution in progress is normal; a distribution in Failed state points at a content library or network issue on the DP. The log to consult is distmgr.log on the site server, which records the state transitions and provider errors.

Targeting and Deployment

With content on the DP, Deploy creates a deployment against a Collection. The fundamental choices are the same as for any ConfigMgr deployment — User Collection vs Device Collection, Available vs Required, deadline, notification behaviour.

A few PSADT-specific notes:

The Enforcement Flow

Understanding what happens when ConfigMgr decides a PSADT package must be installed clarifies both the success path and the failure modes.

  1. Policy evaluation — the ConfigMgr client pulls the application policy from the MP and registers a pending application install.
  2. Requirement evaluation — the client evaluates requirements. A failing requirement ends enforcement with a Requirements not met status and does not escalate to content download.
  3. Content download — the client locates a DP through its boundary group, downloads the content to the local cache (C:\Windows\ccmcache), and verifies the hash.
  4. Detection pre-check — the client runs the detection method first. If the application is already detected, the enforcement is marked as successful immediately without running the install command.
  5. Install execution — the install command (Invoke-AppDeployToolkit.exe -DeploymentType Install ...) is launched in the configured context. Output is captured; exit codes are evaluated against the success/failure/reboot mapping.
  6. Post-enforcement detection — the client runs the detection method a second time, after the install command returns. A detection that reports not installed after a zero exit code is the source of the infamous Past due - will be retried status.
  7. State reporting — the client reports the result to the MP, where the console surfaces it under Monitoring → Deployments.

The enforcement flow matters because different failure modes manifest at different steps. A content hash mismatch fails at step 3. An install error fails at step 5. A detection mismatch fails at step 6. The failure message, and the relevant log, depend on the step.

Logs and Verification

Two sets of logs cover the PSADT deployment cycle: the ConfigMgr client logs and the PSADT-written logs.

Client-Side ConfigMgr Logs

All under C:\Windows\CCM\Logs\:

PSADT Logs

PSADT writes its own logs to a deterministic location so that package authors can attach them to incidents. The default path in recent versions is C:\Windows\Logs\Software\ with a file named after the application and the deployment type, for example MyApp_PSADT_Install.log. The exact filename convention is defined in the toolkit's configuration.

The PSADT log captures:

For troubleshooting an install that returns non-zero, AppEnforce.log identifies the failure moment and the returned code; the PSADT log explains why the vendor installer returned it.

Note
Capturing both logs after a failed deployment — AppEnforce.log and the matching PSADT log — is the irreducible minimum for any packaging incident ticket. Missing either one forces the next analyst to reproduce the issue.

Verifying in Software Center

On the client, Software Center exposes deployment status directly. Installation Status tab lists every application deployment by state. A failed install shows the error code and a truncated message; expanding the entry reveals the full error record. For user-facing diagnostics, this is the end-user-safe interface; for deep analysis, the logs remain primary.

Common Pitfalls

Detection evaluates to not installed after a successful install The install command returned zero but the detection method did not find the expected artifact. Causes range from a mistyped registry key to a version string that differs from the expected value by whitespace. Reading AppDiscovery.log after the enforcement clarifies what the detection actually saw.

Past due - will be retried repeats indefinitely A classic symptom of a mismatched detection method. Every retry installs, detects nothing, and retries again. The fix is always in the detection method, not in the install command.

PSADT dialogs do not appear when expected The Deployment Type's User Experience settings override PSADT's own -DeployMode Interactive argument. If the deployment type is set to Install for system with Whether or not a user is logged on but without Allow users to view and interact, the dialogs are suppressed. Both settings must align.

Install succeeds manually but fails through ConfigMgr Almost always a context difference. Running the install manually typically uses the logged-on user's context; ConfigMgr runs as SYSTEM. Path resolution, HKCU access, and per-user software components behave differently under SYSTEM. The PSADT log, running under SYSTEM, captures what actually happened.

Uninstall never runs The Uninstall command is only executed when the deployment purpose is Uninstall or when the application is superseded by another with Uninstall chosen. An Available deployment that is later removed from the collection does not trigger uninstall.

Dependencies install in the wrong order ConfigMgr resolves dependencies at enforcement time, not at creation time. A dependency chain that worked yesterday can be broken by a superseding deployment elsewhere in the chain. The AppIntentEval.log surfaces the resolution order.

Content not available on the DP at the time of enforcement The Application was deployed before content distribution completed. ConfigMgr dutifully attempts the install, finds no content, and logs a failure. The fix is procedural — distribute first, then deploy.

Vendor installer prompts for UAC even under SYSTEM Some legacy installers request UAC even when not running interactively; the request is auto-denied by the session-zero isolation, and the installer then silently fails. The remedy is an installer-specific silent flag, usually discoverable through the vendor's documentation or by running the installer with /?. PSADT's Start-ADTProcess exposes the arguments cleanly.

Maximum allowed run time expires mid-install A large suite with multiple vendor installers chained in the wrapper can exceed the default 120-minute cap. ConfigMgr terminates the process, and PSADT's log ends abruptly mid-step. Raising the Maximum allowed run time on the deployment type is the correct fix; masking the problem by increasing ConfigMgr's global timeout affects every deployment.

Takeaways

PSADT 4 and ConfigMgr's Application model are a tested pair. PSADT encapsulates the messiness of vendor installers and produces a clean wrapper; ConfigMgr's Application model provides the metadata, targeting, detection, and state reporting that enterprise deployment requires. The integration surface between the two is small — the entry-point executable, its arguments, and the detection method — but getting each of those three right is what separates a reliable deployment from a chronic source of incident tickets.

Detection is the most important of the three and the most frequently misconfigured. Every hour spent refining the detection method saves days of investigating Past due - will be retried statuses in production. MSI product codes remain the gold standard when available; registry-based detections are a strong second; custom PowerShell detections fill the gaps but require careful output handling.

Logs are the second most important discipline. AppEnforce.log and the PSADT log together cover every scenario; reading them in order — ConfigMgr first to identify the moment of failure, PSADT second to understand the vendor installer's behaviour — is a repeatable diagnostic pattern that scales across any packaged product.

Rule of thumb: Detection first, deploy mode second, run-time cap third. When a PSADT 4 application misbehaves in ConfigMgr, these three settings are the root cause in the overwhelming majority of real-world incidents.


Tested with: Configuration Manager Current Branch 2503 on Windows Server 2025, PSADT 4 on Windows 11 24H2 clients, mixed MSI and EXE vendor installers.

SCCM ConfigMgr PSADT Application Deployment Packaging Detection Methods Enterprise
M

Miloch

Enterprise IT, SCCM & ConfigMgr, PowerShell & Automation — building systems right.