---
title: "Deploy software"
description: "Install, upgrade, or remove a catalog package on chosen endpoints, sites, or device groups, and follow each endpoint's result."
url: "https://support.outpostplatform.com/automation/deploy-software/"
product: "depot"
type: "how-to"
status: "draft"
ai_summary: "Deploy a software catalog package from Software > Deployments > New deployment: choose the package, version for uploaded installers, and action (Install, Upgrade, Remove), then endpoints, sites, or device groups. Offline endpoints have three days. Results are one row per endpoint. Upgrade from Software > Inventory. Needs software:deploy."
availability:
  plans: ["home-lab", "essentials", "enterprise", "msp"]
  platforms: ["windows", "linux", "macos"]
  permission: "software:deploy"
  preview: false
source: "https://gitlab.com/outpostplatform/docs/-/edit/main/src/content/docs/automation/deploy-software.md"
license: "CC BY 4.0"
---

# Deploy software

This page sends a package from the software catalog to endpoints and shows
how to read the result. You finish with the package installed, upgraded, or
removed on each endpoint you chose, and a row per endpoint saying how it went.
To add the package to the catalog first, see
[Software catalog and self-service](/automation/software/).

## Before you begin

- You need the `software:deploy` permission.
- On the MSP plan, open the client's workspace first.
- The package's source must suit the endpoints: winget, Chocolatey, uploaded
  installers, and vendor URLs for Windows, apt or dnf for Linux, and Homebrew or
  a Mac installer for macOS. An endpoint of the wrong kind refuses the install
  and says why.

## Deploy a package

1. Go to **Software** > **Deployments** and select **New deployment**.
2. Under **What to send**, choose the **Package**.
3. For an uploaded installer, choose the **Version**, or leave **Newest
   uploaded**. Other sources install whatever the package manager or the vendor
   serves, unless the entry holds the fleet at a version.
4. In **Action**, choose **Install**, **Upgrade**, or **Remove**.
5. Under **Where it goes**, choose endpoints, sites, or device groups. See
   [Run scripts on endpoints](/automation/run-scripts/#run-a-script-now) for the
   same picker.
6. Select **Review**. The summary names what is sent and where. For a site or
   device group, the exact endpoints are worked out when the deployment is
   created.
7. Select **Deploy**.

An endpoint that is offline still takes the deployment. The command waits
three days for it to come back, then expires.

Installing a package that a profile blocks for an endpoint, through
`software.blocked_packages`, is refused, and the message names the setting to
clear. Removing software is never refused.

To remove a package that no package manager owns, such as an uploaded
installer, Outpost uses the uninstall entry each endpoint reported in its
inventory: the first machine-wide install whose name contains the catalog
entry's **Name**. Endpoints without one are left out of the deployment. When no
selected endpoint has one, nothing is sent and the console says **Outpost can't
find an uninstall entry for this app on that endpoint, so it can't remove it.**
For several endpoints it reads **on those endpoints**. An uploaded package can be removed even after its installers were deleted.

## Upgrade what is already installed

1. Go to **Software** > **Inventory**.
2. Narrow the list to the product and select the installs to upgrade.
3. Select **Upgrade selected**, then in **Catalog package**, choose the package
   to upgrade to. Outpost fills it in when every selected install reports the same
   package id.
4. Select **Review**, then **Upgrade**.

An install marked **Per user** is in one person's profile, and only that
person's session can upgrade or remove it.

## Verify

**Software** > **Deployments** lists one row per endpoint with the **Package**,
**Endpoint**, **Action**, **State**, **Started**, and **Finished**. A row that
succeeded shows **Installed**. Other states are **Waiting**, **Sent**,
**Running**, **Failed**, **Timed out**, **Canceled**, and **Expired**. Select
**The rest of this rollout** on a row to see the other endpoints in the same
deployment.

An install succeeds only when every detection check on the catalog entry passes
afterwards, so **Installed** means Outpost found the software on the endpoint.

## If something goes wrong

| Symptom | Cause | Fix |
| --- | --- | --- |
| The deployment is refused because the package is on the blocked software list | A profile that applies lists it in `software.blocked_packages`. | Clear it from the profile, or narrow the selection. |
| A row shows **Failed** on a Windows endpoint for a winget package | winget is not installed, which is common on Windows Server. | Use another source, or set `software.winget_bootstrap_package_id`. See the [Software settings](/automation/policy-settings/#software). |
| A row shows **Failed** although the installer ran | A detection check did not pass. | Check the paths and values under **How Outpost checks it worked** on the catalog entry. |
| A row shows **Expired** | The endpoint stayed offline for three days. | Deploy again when it is online. |
| A removal is refused with **Outpost can't find an uninstall entry for this app on that endpoint, so it can't remove it.** | The endpoint's inventory has no machine-wide install whose name contains the catalog entry's name. A per-user install has no machine-wide entry. | Check **Software** > **Inventory** for the endpoint. Remove a per-user install from that person's session. |

## Next steps

- [Software catalog and self-service](/automation/software/)
- [Patching](/automation/patching/)
