The PSADT.Extension ‘Remove-Applications’ can be used to uninstall software entered in ‘Add- Remove Programs’ with the original Unistall parameters and also Silent with the help of simple filters.
Features:
- Filter by name, manufacturer, version
- Use the original uninstall parameters or not
- Replacing some original uninstall parameters
- Inclusion of special ‘silent’ parameters
- Different debug levels
- IgnoreExit codes
- Return of the ExitCodes
Function Remove-Applications{
<#
.SYNOPSIS
Uninstall Applications listed in Add-Remove-Programs
.DESCRIPTION
with this function is it possible to find and uninstall a Application with the original uninstall-parameters and in Silent-Mode.
.SYNTAX
Remove-Applications [-appName] <String> [-appVendor] <String> [[-appVersion] <String>] [[-SilentParameter] <String>] [[-RemoveOriginalUninstallParameter]<switch>] [[-IgnoreExitCodes] <String>] [[-ContinueOnError] <boolean>] [[-PassThru] <boolean>] [[-Debuglevel] <Int>]
.PARAMETER appName
the Characters the Application-Name starts with. The Parameter is Mandatory. appName="Android"
.PARAMETER appVendor
the Characters the Vendor of the Application-Name starts with. The Parameter is Mandatory. appVendor="Googl"
.PARAMETER appVersion
the Characters the DisplayVersion of the Application-Name starts with. The Parameter is optional. appVersion="12.07"
.PARAMETER SilentParameter
the Parameter to uninstall the Software in SilendMode. The Parameter is optional. If not set the uninstallation will not be silent. SilentParameter="/Silent"
.PARAMETER RemoveOriginalUninstallParameter
Removes all existing UninstallParameters "Uninstall.exe" /U /S /X -> "Uninstall.exe"
.PARAMETER ReplaceSomeOriginalUninstallParameter
Replace some Uninstall Parameters "$find>$Repalce","$find>$Repalce" The '>' is the seperator between find ans replace string
"/U>/S","C:>D:"
.PARAMETER Debuglevel
if the debuglevel is higher then 0 debuginformations will be written in the 'Custom Log'. The Parameter is optional. default=0
0=no debug , 1=only ReturnValue , 2=full debug with most values
.PARAMETER IgnoreExitCodes
List the exit codes to ignore.
.PARAMETER ContinueOnError
Continue if an exit code is returned by the process that is not recognized by the App Deploy Toolkit. Default: $false.
.PARAMETER PassThru
Returns ExitCode, STDOut, and STDErr output from the process.
.PARAMETER NoWait
Immediately continue after executing the process.
.EXAMPLE
Remove-Applications "Android" "Googl" "12." "/Silent"
.EXAMPLE
Remove-Applications "Android" "Googl" 2 -> no silent uninstall
.EXAMPLE
Remove-Applications -appName "Android" -appVendor "Googl" -appVersion "12.07" -SilentParameter "/S /Z" -Debuglevel 2
.EXAMPLE
Execute-Process -Path 'setup.exe' -Parameters '/S' -IgnoreExitCodes '1,2'
.NOTES
Attention: You must find out the Silent-Parameter by yourself and put it in the SilentParameter.
Attention: If you chose -appName "Microsoft" -appVendor "Microsoft" as Parameter the most Microsoft-Software will be uninstalled
Author of this feature: Steffen Hoffmann
#>
Param(
[Parameter(Mandatory=$true)][String]$appName,
[String]$appVendor,
[String]$appVersion,
[String]$SilentParameter,
[switch]$RemoveOriginalUninstallParameter,
[String]$ReplaceSomeOriginalUninstallParameter,
[Parameter(Mandatory=$false)]
[ValidateNotNullorEmpty()]
[string]$IgnoreExitCodes,
[Parameter(Mandatory=$false)]
[ValidateNotNullorEmpty()]
[boolean]$ContinueOnError = $false,
[Parameter(Mandatory=$false)]
[switch]$PassThru = $false,
[Parameter(Mandatory=$false)]
[switch]$NoWait = $false,
[Int]$Debuglevel=0
)
If($Debuglevel -ge 2){
Write-Log -Message "Remove-Applications - all given parameters:" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "appName: $appName" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "appVendor: $appVendor" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "appVersion: $appVersion" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "SilentParameter: $SilentParameter" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "RemoveOriginalUninstallParameter: $RemoveOriginalUninstallParameter" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "IgnoreExitCodes: $IgnoreExitCodes" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "ContinueOnError: $ContinueOnError" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "PassThru: $PassThru" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "NoWait: $NoWait" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "Debuglevel: $Debuglevel" -Source 'Custom Log' -LogType 'CMTrace'
}
If($Debuglevel -ge 1){
Write-Log -Message "Enum Installed $appVendor $appName $appVersion Software. Look for Uninstall Path" -Source 'Custom Log' -LogType 'CMTrace'
}
$InstSoftwareVersion = @()
IF($appName){
# Enum Installed 64Bit Software that matched die appName
$64bit = get-itemproperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' -Name DisplayName, DisplayVersion, Publisher, InstallDate, HelpLink, UninstallString, InstallLocation -ErrorAction SilentlyContinue | where-Object -FilterScript {$_.DisplayName -like "$appName*" -and $_.Publisher -like "$appVendor*" -and $_.DisplayVersion -like "$appVersion*"} | Select DisplayName, DisplayVersion, Publisher, InstallDate, HelpLink, UninstallString
# Enum Installed 32Bit Software that matched die appName
$32bit = get-itemproperty 'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' -Name DisplayName, DisplayVersion, Publisher, InstallDate, HelpLink, UninstallString, InstallLocation -ErrorAction SilentlyContinue | where-Object -FilterScript {$_.DisplayName -like "$appName*" -and $_.Publisher -like "$appVendor*" -and $_.DisplayVersion -like "$appVersion*"} | Select DisplayName, DisplayVersion, Publisher, InstallDate, HelpLink, UninstallString
if ($32bit){
Write-Log -Message "$32bit" -Source 'Custom Log' -LogType 'CMTrace'
}
else{
Write-Log -Message "No 32Bit Applications found" -Source 'Custom Log' -LogType 'CMTrace'
}
if ($64bit){
Write-Log -Message "$64bit" -Source 'Custom Log' -LogType 'CMTrace'
}
else{
Write-Log -Message "No 64Bit Applications found" -Source 'Custom Log' -LogType 'CMTrace'
}
# Check if a used Value is not empty
if($32bit){
if($64bit){
$InstSoftwareVersion += $32bit
$InstSoftwareVersion += $64bit
}
else
{
$InstSoftwareVersion += $32bit
}
}
else
{
if($64bit)
{
$InstSoftwareVersion += $64bit
}
}
If($Debuglevel -ge 2){
Write-Log -Message "Found Installed Software Values" -Source 'Custom Log' -LogType 'CMTrace'
if($InstSoftwareVersion){Write-Log -Message $InstSoftwareVersion -Source 'Custom Log' -LogType 'CMTrace'}
}
#$all = $32bit + $64bit
If($Debuglevel -ge 2){
Write-Log -Message "Show Found DisplayNames and UninstallString" -Source 'Custom Log' -LogType 'CMTrace'
$InstSoftwareVersion |foreach-Object{
if($_){
Write-Log -Message $_.DisplayName -Source 'Custom Log' -LogType 'CMTrace'
if(![string]::IsNullOrEmpty($_.UninstallString)){
Write-Log -Message $_.UninstallString -Source 'Custom Log' -LogType 'CMTrace'
}
}
}
}
# Clear ReturnValue
$ReturnValue = @()
if($InstSoftwareVersion){
# Do each entry in found Software
$InstSoftwareVersion |foreach-Object{
If($Debuglevel -ge 2){
Write-Log -Message "Show details for each Entry" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "--------------------------------------------" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $_.DisplayName -Source 'Custom Log' -LogType 'CMTrace'
if($_.UninstallString){
Write-Log -Message $_.UninstallString -Source 'Custom Log' -LogType 'CMTrace'
}
}
# Test the uninstallstring and figure out the Uninstallstring and the Parameters
if($_.UninstallString){
# If Uninstallstring starts with quotation marks
if($_.UninstallString.StartsWith('"'))
{
$UninstallStr=$_.UninstallString.ToString().Substring(0,$_.UninstallString.IndexOf('"',1)+1)
$UninstallPar=$_.UninstallString.ToString().Substring($_.UninstallString.IndexOf('"',1)+1)
if (!$RemoveOriginalUninstallParameter){
$UninstallPar=$UninstallPar.Trim()
}else{
$UninstallPar=""
}
if (!$ReplaceSomeOriginalUninstallParameter){
$UninstallPar=$UninstallPar.Trim()
}else{
$ReplacePares=$ReplaceSomeOriginalUninstallParameter
"hello"
$ReplacePares
foreach ($ReplacePare in $ReplacePares)
{
"2"
$ReplacePare
$ReplaceSourceDest= $ReplacePare -split ">"
$ReplaceSource = $ReplaceSourceDest[0]
"3"
$ReplaceSource
$RecoureDest = $ReplaceSourceDest[1]
"4"
$RecoureDest
$UninstallPar = $UninstallPar.replace($ReplaceSource,$RecoureDest)
$UninstallPar
}
}
$rc1 = New-Object PSCustomObject
$rc1 | Add-Member -type NoteProperty -name DisplayName -Value $_.DisplayName
$rc1 | Add-Member -type NoteProperty -name Publisher -Value $_.Publisher
$rc1 | Add-Member -type NoteProperty -name DisplayVersion -Value $_.DisplayVersion
$rc1 | Add-Member -type NoteProperty -name UninstallString -Value $UninstallStr
$rc1 | Add-Member -type NoteProperty -name UninstallParameters -Value $UninstallPar
$ReturnValue += $rc1
If($Debuglevel -ge 2){
Write-Log -Message "Uninstallstring starts with quotation marks" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "UninstallStr: $UninstallStr" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "UninstallPar: $UninstallPar" -Source 'Custom Log' -LogType 'CMTrace'
}
#Write-Host "UninstallStr: $UninstallStr" -ForegroundColor yellow
#Write-Host "UninstallPar: $UninstallPar"
}
elseif($_.UninstallString.StartsWith('MsiExec'))
{
$UninstallStr = "MsiExec.exe"
$UninstallPar = $_.UninstallString.Replace($UninstallStr , "").Trim()
if (!$RemoveOriginalUninstallParameter){
$UninstallPar=$UninstallPar.Trim()
}else{
$UninstallPar=""
}
if (!$ReplaceSomeOriginalUninstallParameter){
$UninstallPar=$UninstallPar.Trim()
}else{
$ReplacePares=$ReplaceSomeOriginalUninstallParameter
"hello"
$ReplacePares
foreach ($ReplacePare in $ReplacePares)
{
"2"
$ReplacePare
$ReplaceSourceDest= $ReplacePare -split ">"
$ReplaceSource = $ReplaceSourceDest[0]
"3"
$ReplaceSource
$RecoureDest = $ReplaceSourceDest[1]
"4"
$RecoureDest
$UninstallPar = $UninstallPar.replace($ReplaceSource,$RecoureDest)
$UninstallPar
}
}
$rc1 = New-Object PSCustomObject
$rc1 | Add-Member -type NoteProperty -name DisplayName -Value $_.DisplayName
$rc1 | Add-Member -type NoteProperty -name Publisher -Value $_.Publisher
$rc1 | Add-Member -type NoteProperty -name DisplayVersion -Value $_.DisplayVersion
$rc1 | Add-Member -type NoteProperty -name UninstallString -Value $UninstallStr
$rc1 | Add-Member -type NoteProperty -name UninstallParameters -Value $UninstallPar
$ReturnValue += $rc1
If($Debuglevel -ge 2){
Write-Log -Message "Uninstallstring starts with MsiExec.exe" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "UninstallStr: $UninstallStr" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "UninstallPar: $UninstallPar" -Source 'Custom Log' -LogType 'CMTrace'
}
#Write-Host "UninstallStr: $UninstallStr" -ForegroundColor yellow
#Write-Host "UninstallPar: $UninstallPar"
}
else
{
If($Debuglevel -ge 2){
Write-Log -Message "Uninstallstring with or without Spaces" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $_.UninstallString -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "Find the Path to the Unistall-Program. The Uninstall-Program-Name must end with an .exe" -Source 'Custom Log' -LogType 'CMTrace'
}
$UninstallSpl=$_.UninstallString.Split(" ")
#$UninstallSpl
$i = 0
$UninstallStr = $UninstallSpl[0]
If($Debuglevel -ge 2){
Write-Log -Message "Start with Path:" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $UninstallStr -Source 'Custom Log' -LogType 'CMTrace'
}
while (!(Test-Path "$UninstallStr") -or (!($UninstallStr.EndsWith(".exe"))))
{
$i++
#$i
if ($i -ge $UninstallSpl.length) {break}
$Helper = $UninstallSpl[0 .. $i]
$UninstallStr = ""
foreach ($element in $Helper)
{
$UninstallStr += ' ' + $element
$UninstallStr = $UninstallStr.Trim()
}
If($Debuglevel -ge 2){
Write-Log -Message "Next Path to test:" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $UninstallStr -Source 'Custom Log' -LogType 'CMTrace'
}
#$UninstallStr
}
If($Debuglevel -ge 2){
if ($UninstallStr.EndsWith(".exe")){
Write-Log -Message "Uninstall-Program found:" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $UninstallStr -Source 'Custom Log' -LogType 'CMTrace'
}else{
Write-Log -Message "No Uninstall-Program found" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "Last Path checked:" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $UninstallStr -Source 'Custom Log' -LogType 'CMTrace'
}
}
if ($i -ge $UninstallSpl.length)
{
if ($_.UninstallString.StartsWith("RunDll32"))
{
$UninstallStr = "RunDll32"
}
if ($_.UninstallString.StartsWith("RunDll32.exe"))
{
$UninstallStr = "RunDll32.exe"
}
}
$UninstallPar = $_.UninstallString.Replace($UninstallStr , "").Trim()
if (!$RemoveOriginalUninstallParameter){
$UninstallPar=$UninstallPar.Trim()
}else{
$UninstallPar=""
}
if (!$ReplaceSomeOriginalUninstallParameter){
$UninstallPar=$UninstallPar.Trim()
}else{
$ReplacePares=$ReplaceSomeOriginalUninstallParameter
"hello"
$ReplacePares
foreach ($ReplacePare in $ReplacePares)
{
"2"
$ReplacePare
$ReplaceSourceDest= $ReplacePare -split ">"
$ReplaceSource = $ReplaceSourceDest[0]
"3"
$ReplaceSource
$RecoureDest = $ReplaceSourceDest[1]
"4"
$RecoureDest
$UninstallPar = $UninstallPar.replace($ReplaceSource,$RecoureDest)
$UninstallPar
}
}
if ($UninstallStr.endswith(".exe") -or ($UninstallStr.StartsWith("RunDll32")))
{
$rc1 = New-Object PSCustomObject
$rc1 | Add-Member -type NoteProperty -name DisplayName -Value $_.DisplayName
$rc1 | Add-Member -type NoteProperty -name Publisher -Value $_.Publisher
$rc1 | Add-Member -type NoteProperty -name DisplayVersion -Value $_.DisplayVersion
$rc1 | Add-Member -type NoteProperty -name UninstallString -Value $UninstallStr
$rc1 | Add-Member -type NoteProperty -name UninstallParameters -Value $UninstallPar
$ReturnValue += $rc1
If($Debuglevel -ge 2){
Write-Log -Message "Uninstallstring starts with .exe or RunDll32" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "UninstallStr: $UninstallStr" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "UninstallPar: $UninstallPar" -Source 'Custom Log' -LogType 'CMTrace'
}
#Write-Host "UninstallStr_With_EXE: $UninstallStr" -ForegroundColor yellow
#Write-Host "UninstallPar: $UninstallPar"
}
}
}
}
}
}
If($Debuglevel -ge 1){
Write-Log -Message "Returnvalue:" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message $ReturnValue -Source 'Custom Log' -LogType 'CMTrace'
}
$ReturnValue |foreach-Object{
$ExitProcessParameters = @{}
if ($PSBoundParameters.ContainsKey('IgnoreExitCodes'))
{
Write-Log -Message "Remove-Applications-IgnoreExitCodes: $IgnoreExitCodes" -Source 'Custom Log' -LogType 'CMTrace'
$ExitProcessParameters.Add("IgnoreExitCodes",$IgnoreExitCodes)
}
if ($PSBoundParameters.ContainsKey('ContinueOnError'))
{
Write-Log -Message "Remove-Applications-ContinueOnError: $ContinueOnError" -Source 'Custom Log' -LogType 'CMTrace'
$ExitProcessParameters.Add("ContinueOnError",$ContinueOnError)
}
if ($PSBoundParameters.ContainsKey('PassThru'))
{
Write-Log -Message "Remove-Applications-PassThru: $PassThru" -Source 'Custom Log' -LogType 'CMTrace'
$ExitProcessParameters.Add("PassThru",$PassThru)
}
if ($PSBoundParameters.ContainsKey('NoWait'))
{
Write-Log -Message "Remove-Applications-NoWait: $NoWait" -Source 'Custom Log' -LogType 'CMTrace'
$ExitProcessParameters.Add("NoWait",$NoWait)
}
#Write-Log -Message "True/False:" -Source 'Custom Log' -LogType 'CMTrace'
#Write-Log -Message $_.UninstallString -Source 'Custom Log' -LogType 'CMTrace'
if($_.UninstallString.StartsWith('"'))
{
#$UninTest = $_.UninstallString.ToString().Substring(1,$_.UninstallString.Length-2)
$UninsStr=$SilentParameter + " " + $_.UninstallParameters
$ExitProcessParameters.Add("Path",$_.UninstallString.ToString().Substring(1,$_.UninstallString.Length-2))
$PathToTest = $_.UninstallString.ToString().Substring(1,$_.UninstallString.Length-2)
$ExitProcessParameters.Add("Parameters",$UninsStr)
If($Debuglevel -ge 2){
Write-Log -Message "1-Execute-Process $ExitProcessParameters" -Source 'Custom Log' -LogType 'CMTrace'
}
IF(Test-Path -Path "$PathToTest"){
Execute-Process @ExitProcessParameters
#Execute-Process -Path $_.UninstallString.ToString().Substring(1,$_.UninstallString.Length-2) -Parameters $UninsStr
}
}elseif($_.UninstallString.StartsWith('MsiExec'))
{
If($Debuglevel -ge 2){
Write-Log -Message "2-Remove-MSIApplicationsCustom -Name $_.DisplayName -Publischer $_.Publisher -DisplayVersion $_.DisplayVersion" -Source 'Custom Log' -LogType 'CMTrace'
}
Remove-MSIApplicationsCustom -Name $_.DisplayName -FilterApplication (('Publisher', $_.Publisher, 'Exact'),('DisplayVersion', $_.DisplayVersion, 'Exact'))
}elseif($_.UninstallString -eq 'RunDll32.exe')
{
#$UninsStr=$SilentParameter + " " + $_.UninstallParameters
$UninsStr=$_.UninstallParameters + " " + $SilentParameter
$ExitProcessParameters.Add("Path",$_.UninstallString)
$PathToTest = $envWinDir + "\system32\" + $_.UninstallString
$ExitProcessParameters.Add("Parameters",$UninsStr)
If($Debuglevel -ge 2){
Write-Log -Message "3-Execute-Process $ExitProcessParameters" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "PathToTest: $PathToTest" -Source 'Custom Log' -LogType 'CMTrace'
}
IF(Test-Path -Path "$PathToTest"){
Execute-Process @ExitProcessParameters
#Execute-Process -Path $_.UninstallString -Parameters $UninsStr
}
}elseif($_.UninstallString -eq 'RunDll32')
{
#$UninsStr=$SilentParameter + " " + $_.UninstallParameters
$UninsStr=$_.UninstallParameters + " " + $SilentParameter
$ExitProcessParameters.Add("Path",$_.UninstallString + ".exe")
$PathToTest = $envWinDir + "\system32\" + $_.UninstallString + ".exe"
$ExitProcessParameters.Add("Parameters",$UninsStr)
If($Debuglevel -ge 2){
Write-Log -Message "4-Execute-Process $ExitProcessParameters" -Source 'Custom Log' -LogType 'CMTrace'
Write-Log -Message "PathToTest: $PathToTest" -Source 'Custom Log' -LogType 'CMTrace'
}
IF(Test-Path -Path "$PathToTest"){
Execute-Process @ExitProcessParameters
#Execute-Process -Path $_.UninstallString + ".exe" -Parameters $UninsStr
}
}elseif([string]::IsNullOrEmpty($InstSoftwareVersion.UninstallString)){
If($Debuglevel -ge 2){
Write-Log -Message "5-Uninstall-String is Empty - No Uninstall possible with this way." -Source 'Custom Log' -LogType 'CMTrace'
}
}else
{
$UninsStr=$SilentParameter + " " + $_.UninstallParameters
$ExitProcessParameters.Add("Path",$_.UninstallString)
$PathToTest = $_.UninstallString
$ExitProcessParameters.Add("Parameters",$UninsStr)
If($Debuglevel -ge 2){
Write-Log -Message "6-Execute-Process $ExitProcessParameters" -Source 'Custom Log' -LogType 'CMTrace'
}
IF(Test-Path -Path "$PathToTest"){
Execute-Process @ExitProcessParameters
#Execute-Process -Path $_.UninstallString -Parameters $UninsStr
}
}
}
#return $ReturnValue
}