Overview
A simple PowerShell template designed for use with SCCM/MECM to install exe/msi based applications. Highlights include:
- Option to uninstall an existing application prior to install (Useful in scenarios where the application has previously been installed manually.)
- Application detection logic built-in to determine the appropriate exit code.
- Sets a registry item with the date of install if the process completes successfully. This registry item can also be used as an Application Detection Method for SCCM.
- Generates a log file.
How to use
Configure the following script variables:
- $PackageName – Create a friendly package name. This will be used to generate the registry entry to use as an SCCM Application Detection Method. As a sample, you can see I’ve named the app according to vendor, product, version etc.
- $SoftwareDetectionPath – Keep the path configured if you’re happy with the location. Otherwise, feel free to specify your own. This is used to create a registry key following a successful install. This key should be used as an SCCM Application Detection Method.
- $UninstallExisting – Set either $true or $false. Enables the option to uninstall an existing application if it exists on the client device.
- $RegistryDisplayName – The name of the application as appears in the registry for the current application. See the example in the script below for more details on how you can retrieve the Display Name for the application you wish to uninstall prior to installation.
- $Installers –
- InstallFile – The name of each installation msi/exe.
- InstallArguments – The install parameters required for a silent installation for each installer.
- RegistryDisplayName – Used for the install verification logic. See the sample in the script for more information on how to use.
Save your script as install.ps1. Follow methodologies used to create an Application in SCCM. See here for more details.
Navigate to your SCCM Application properties. Configure your install script using the following command:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Powershell.exe -ExecutionPolicy ByPass -File install.ps1 |

Under the Detection Method tab, select edit under Use a Custom Script to Detect the Presence of this Application Type. Replace PackageName with the value you entered for the $PackageName variable in your install script earlier.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $packageFound = Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Software Distribution" -Name "PackageName" -ErrorAction SilentlyContinue | |
| if ($packageFound){ write-host "Installed"} |

Feel free to use the script below as a template and modify as you wish. If you have any questions, comment below.
Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ApplicationPackaging_PackageInstallerTemplate | |
| #Version | 1.0 | |
| #Contact | Josh Woods | joshua@jwblog.uk | |
| #References | |
| #https://techgenix.com/how-to-uninstall-software-using-powershell/ | |
| ################### | |
| #Variables | |
| ################### | |
| #Configuration | |
| $PackageName = "Microsoft_PowerBI_1.0_64_MSI_R01" | |
| $SoftwareDetectionPath = "HKLM:\SOFTWARE\Software Distribution" | |
| #Uninstall | |
| $UninstallExisting = $false | |
| #Uninstall | |
| #Retrieve Registry Display name by locating the version you need to uninstall from either of the following two paths: | |
| #(Get-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | Select-object DisplayName, DisplayVersion | sort-object) | |
| #(Get-ItemProperty -path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' | Select-object DisplayName, DisplayVersion | sort-object) | |
| #Get-ItemProperty -path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' | where-object {$_.DisplayName -Like "*WinRAR*"} | |
| #Get-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where-object {$_.DisplayName -Like "*WinRAR*"} | |
| $Uninstallers = @( | |
| [pscustomobject]@{RegistryDisplayName='WinRAR 6.23 (64-bit)';RegistryDisplayVersion='6.23.0';UninstallStringDir='C:\Program Files\WinRAR\uninstall.exe';UninstallStringArguments='/s'} #Must be placed in the same directory as this script | |
| [pscustomobject]@{RegistryDisplayName='';RegistryDisplayVersion='';UninstallStringDir='';UninstallStringArguments=''} | |
| ) | |
| #Install | |
| #Retrieve Registry Display name by locating the version you need to uninstall from either of the following two paths: | |
| #(Get-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | Select-object -expandproperty DisplayName | sort-object) | |
| #(Get-ItemProperty -path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' | Select-object -expandproperty DisplayName | sort-object) | |
| $Installers = @( | |
| [pscustomobject]@{InstallFile='PowerBI.exe';InstallArguments='/QN /norestart';RegistryDisplayName='PowerBI'} #Must be placed in the same directory as this script | |
| [pscustomobject]@{InstallFile='';InstallArguments='';RegistryDisplayName=''} | |
| ) | |
| ################### | |
| #Variables End | |
| ################### | |
| #Stop Install on Error and output to log | |
| try { | |
| #Log | |
| #Start Log Transcript | |
| Start-Transcript -Path "C:\Windows\Logs\$PackageName.txt" -append | |
| if ($UninstallExisting -eq $true) { | |
| ######################################################################################################################################################################################################################################## | |
| #This section will uninstall a previous version based on the $RegistryDisplayName variable which uses the applications DisplayName. | |
| ######################################################################################################################################################################################################################################## | |
| foreach ($Uninstall in $Uninstallers) { | |
| #Run Uninstall String | |
| Write-Output "Uninstalling $($Uninstall.RegistryDisplayName) based on Uninstall String…" | |
| Start-Process "$($Uninstall.UninstallStringDir)" -ArgumentList "$($Uninstall.UninstallStringArguments)" -Wait | |
| } | |
| } | |
| else { | |
| #Run Uninstall String | |
| Write-Output "Uninstalling $($Uninstaller.RegistryDisplayName) based on Uninstall String…" | |
| Start-Process "$($Uninstallers.UninstallStringDir)" -ArgumentList "$($Uninstallers.UninstallStringArguments)" -Wait | |
| } | |
| ######################################################################################################################################################################################################################################## | |
| #This section will Install the App and set the detection registry entry | |
| ######################################################################################################################################################################################################################################## | |
| foreach ($Installer in $Installers) { | |
| #Install/Upgrade | |
| Write-Output "Installing $($Installer.InstallFile)" | |
| Start-Process "$PSScriptRoot\$($Installer.InstallFile)" -ArgumentList "$($Installer.InstallArguments)" -Wait | out-null | |
| #Verify Installation | |
| $Verify1 = Get-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' | where-object DisplayName -eq "$($Installer.RegistryDisplayName)" | |
| $Verify2 = Get-ItemProperty -path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' | where-object DisplayName -eq "$($Installer.RegistryDisplayName)" | |
| if (($Verify1.DisplayName -eq "$($Installer.RegistryDisplayName)") -or ($Verify2.DisplayName -eq "$($Installer.RegistryDisplayName)")) { | |
| #Success | |
| Write-Output "Successfully Installed $($Installer.InstallFile)" | |
| } | |
| else { | |
| Write-Output "Failed to Install $($Installer.InstallFile)" | |
| Exit 1 | |
| } | |
| } | |
| #SCCM Detection Registry Entry | |
| Get-Item -Path "$SoftwareDetectionPath" | Out-Null | |
| if ($?) { | |
| #Do nothing. Registry path already exists | |
| } | |
| else { | |
| New-Item -Path "$SoftwareDetectionPath" | |
| } | |
| #Set Install Confirmation Registry Key | |
| New-ItemProperty -Path "$SoftwareDetectionPath" -Name "$PackageName" -PropertyType "String" -Value "Installed on $(Get-Date)" -Force | |
| Start-Sleep -s 10 | |
| #Output Logs to File | |
| Stop-Transcript | |
| } | |
| catch { | |
| #Failed. Write error and exit. | |
| Write-Output "Error: $($_.Exception.Message)" | |
| #Output Logs to File | |
| Stop-Transcript | |
| } | |
