In real-world environments, not all enterprise software comes with a proper installer. Some applications lack MSI packages, silent install options, or any clear deployment documentation.
This becomes a serious challenge when you need to deploy such software across multiple machines using Microsoft SCCM.
In this guide, we’ll build a custom PowerShell-based installer that acts as a smart deployment layer. It will handle version control, remove old or broken installations, and ensure a clean and consistent deployment process.
When You Need This Approach
This approach is especially useful in the following scenarios:
- The application does not provide an MSI installer
- Silent installation is unreliable or undocumented
- Multiple versions of the application exist across devices
- Old versions are not removed automatically during upgrades
- Vendor documentation is limited, outdated, or missing
Solution Overview
Instead of relying on a traditional installer, we will use a PowerShell script as a smart deployment wrapper.
This script introduces logic that is typically missing in poorly packaged software and gives you full control over the installation process.
The installer will:
- Detect whether the application is already installed
- Identify the currently installed version
- Remove outdated, broken, or leftover installations
- Install the required version
- Return proper exit codes for Microsoft SCCM to correctly interpret the result
Let’s See How This Works in a Real SCCM Deployment
Now that we understand the idea behind a smart PowerShell-based installer, let’s walk through how this approach is implemented in a real deployment scenario using Microsoft SCCM.
In this example, we’ll be working with a legacy DLP (Data Loss Prevention) system that does not provide a proper installer, has limited documentation, and is not designed for large-scale deployment.
We’ll start by creating a new application, which will later use our custom PowerShell script as the installation engine.
In the SCCM console, navigate to:
Software Library → Application Management → Applications
From there, select Create Application to begin the process.

After launching the Create Application Wizard in Microsoft SCCM, you’ll be prompted to specify how the application information should be configured.
At first glance, it might seem that automatic detection could be used, since the DLP solution does provide an MSI package.
However, in this case, the MSI alone is not sufficient.
The application has multiple versions deployed across the environment, each with a different ProductCode but the same display name. Additionally, the installer requires custom parameters, and older versions are not properly removed during upgrades.
Because of this, relying on SCCM’s built-in MSI detection and upgrade logic would require multiple detection rules and complex configuration.
Instead, we take a different approach:
We select Manually specify the application information and move all logic into a PowerShell-based installer.

Next, we proceed to the General Information section of the application configuration in Microsoft SCCM.
Here, you define basic metadata for the application, such as the name, publisher, and administrative contacts.

In this example, the Owners and Support contacts fields are populated for internal tracking and operational visibility.
While these fields are optional, it is considered a good practice to include them in enterprise environments. This helps identify responsible teams and simplifies support and troubleshooting later on.
Next, we configure how the application will appear to end users in the Software Center within Microsoft SCCM.
This step allows you to define user-facing details such as the application name, description, and additional metadata.

In this example, we provide a simple application name (DLPAgent) to make it easily recognizable.
Most of the other fields, such as user documentation, privacy URL, or detailed description, are optional and can be filled based on your organization’s requirements.
Next, move to the Deployment Types step in Microsoft SCCM.
Here, we define how the application will be installed.
Click Add to create a new Deployment Type.

After clicking Add, the Create Deployment Type Wizard will open.
At this step, select:
Manually specify the deployment type information

This allows us to define a custom installation method, which we will use to integrate our PowerShell-based installer logic.
Next, define basic information for the Deployment Type.
Provide a name and optional description to identify the installation method.

These fields are mainly used for internal reference and do not affect the installation logic.
Next, configure the Content section of the Deployment Type.
Here, you specify where the installation files are located and how the application should be installed and uninstalled.

For the Content location, always use a UNC network path (for example: \\server\share\folder) rather than a local path.
This ensures that Microsoft SCCM can properly distribute the content to clients.
In this example, we use PowerShell scripts as the installation mechanism:
Installation program:
powershell.exe -ExecutionPolicy Bypass -File .\installdlp.ps1
Uninstall program:
powershell.exe -ExecutionPolicy Bypass -File .\uninstalldlp.ps1
This allows us to fully control the installation process, including version checks, cleanup of old installations, and applying custom parameters, all handled inside the script.
Next, configure the Detection Method, which determines whether the application is already installed on the device.

Click Add Clause to define a detection rule.
In our case, we keep the detection logic simple and check only for the new (target) version of the application.
This is intentional.
All version handling, cleanup, and upgrade logic is already implemented in the PowerShell installer. Because of that, we don’t need multiple complex detection rules in Microsoft SCCM.
The result is:
- If the new version is installed → SCCM will detect the application and skip installation
- If any older version (or no version) is installed → SCCM will trigger the installer
After configuring the detection rule, click OK to apply the settings.

At this point, the detection method is complete and ready to be used by Microsoft SCCM during deployment.

Next, configure the User Experience settings.

In this setup, we use:
- Install for system
- Whether or not a user is logged on
- Hidden installation
This ensures that the installation runs silently in the background and does not require user interaction, which is the recommended approach for enterprise deployments via Microsoft SCCM.
Next, configure Requirements for the deployment.


In this example, the application is limited to:
- Windows 10 (x64)
- Windows 11 (x64)
This ensures that the deployment will only run on supported operating systems in Microsoft SCCM.
Next, review the Dependencies section.

In this case, no dependencies are required, so this step can be skipped.
Finally, review the Summary of the Deployment Type configuration.

Verify that all settings are correct, then click Next to proceed.

PowerShell Installer Script
Now let’s take a look at the core of this solution: the PowerShell-based installer used by Microsoft SCCM.
This script acts as a smart wrapper around the MSI installer and handles all version control and cleanup logic.
Installation Script
Below is the installation script used in the Installation Program:
# Enable transcript for troubleshooting
Start-Transcript -Path "C:\install_log.txt" -Append
# === CONFIGURATION ===
$TargetName = "DLP Technologies Endpoint Protector" # Software display name to check
$NewVersionGUID = "{6F6F7421-163A-40C6-A542-6D44C3068E45}" # ProductCode of the new version
$MSIPath = Join-Path $PSScriptRoot "DLPEndpointAgent_10.4.msi"
# Custom MSI parameters
$UninstallParams = "/uninstall {0} /q REMOVE_SCANNERSTR=1"
$InstallParams = "/i `"{0}`" /qn MAIN_CONSOLE_ADDRESS=dlpnn.domain.com"
try {
# Find installed DLP software
$installed = Get-WmiObject Win32_Product -ErrorAction Stop |
Where-Object { $_.Name -eq $TargetName }
if (-not $installed) {
Write-Host "No DLP installed. Installing new version..."
if (Test-Path $MSIPath) {
$installArgs = [string]::Format($InstallParams, $MSIPath)
Start-Process "msiexec.exe" -ArgumentList $installArgs -Wait -ErrorAction Stop
} else {
Write-Host "ERROR: MSI file not found at $MSIPath"
}
}
else {
if ($installed.IdentifyingNumber -eq $NewVersionGUID) {
Write-Host "New version already installed. Nothing to do."
}
else {
Write-Host "Different version installed. Removing..."
$uninstallArgs = [string]::Format($UninstallParams, $installed.IdentifyingNumber)
Start-Process "msiexec.exe" -ArgumentList $uninstallArgs -Wait -ErrorAction Stop
Write-Host "Installing new version..."
if (Test-Path $MSIPath) {
$installArgs = [string]::Format($InstallParams, $MSIPath)
Start-Process "msiexec.exe" -ArgumentList $installArgs -Wait -ErrorAction Stop
} else {
Write-Host "ERROR: MSI file not found at $MSIPath"
}
}
}
}
catch {
Write-Host "ERROR: $($_.Exception.Message)"
}
finally {
Stop-Transcript
exit 0 # Always return success for SCCM
}
How It Works
The script implements a simple but powerful logic:
- If the application is not installed → install it
- If an older or different version is installed → remove it and install the new one
- If the correct version is already installed → do nothing
Instead of relying on multiple detection rules in Microsoft SCCM, all version handling is centralized inside the script.
This makes the deployment more predictable and easier to maintain.
Uninstall Script
Below is the script used in the Uninstall Program:
# Name of the software to remove
$TargetName = "DLP Technologies Endpoint Protector"
# Custom MSI uninstall parameters
$UninstallParams = "/uninstall {0} /qn REMOVE_SCANNERSTR=1"
# Find matching software
$installedApp = Get-WmiObject Win32_Product | Where-Object { $_.Name -eq $TargetName }
if ($installedApp) {
Write-Host "Found $TargetName, removing..."
# Prepare uninstall command with ProductCode
$uninstallArgs = [string]::Format($UninstallParams, $installedApp.IdentifyingNumber)
try {
# Start uninstall process and wait for completion
Start-Process -FilePath "msiexec.exe" -ArgumentList $uninstallArgs -Wait -ErrorAction Stop
Write-Host "Uninstall completed successfully."
exit 0
}
catch {
Write-Host "Uninstall failed: $($_.Exception.Message)"
exit 1
}
}
else {
Write-Host "Target software not found. Nothing to do."
exit 0
}
Why This Approach Works
This method solves several common problems:
- Handles multiple versions with different ProductCodes
- Ensures old versions are fully removed before installation
- Supports custom MSI parameters
- Keeps SCCM detection logic simple and reliable
Deployment
At this point, the application is fully configured and ready for deployment in Microsoft SCCM.
You can now create a device collection, add target machines, and deploy the application to that collection.
Once deployed:
- Devices with the correct version installed will be skipped
- Devices with older or missing versions will run the PowerShell installer
- The script will handle cleanup and installation automatically
This approach ensures a consistent and controlled deployment process, even for poorly packaged or legacy applications.
It’s also important to note that this approach is not limited to MSI-based applications.
The same logic can be applied to:
- EXE installers
- Custom setup binaries
- Even fully manual file-based installations
In such cases, only the PowerShell script needs to be adjusted, while the overall application structure in Microsoft SCCM remains unchanged.
This makes the solution flexible and reusable across different types of software and deployment scenarios.

Infrastructure Engineer with hands-on experience in Windows Server, Active Directory, SCCM, Exchange, and Linux environments. Concentrated on resolving production issues and keeping systems stable and reliable.