Massively uninstall applications with PowerShell

Rafael Aguilar 496 Reputation points
2022-02-24T19:14:11.803+00:00

Hello Team.

I have the following script thanks to colleague Garth Jones and it consists of removing applications by doing a search in the registry, specifically from uninstallstring.

I would like to improve it and that instead of being an application it is several at the same time.

Is that possible? So far I have this. Can you guide me where to start?

$appToMatch = @('*zoom*','*vlc*')
$e=$MyInvocation.InvocationName
$pshome
$log=$env:temp+'\PSuninstall.log'
#$fullinventory = $false
#$fullinventory = $true

#function Start-HWInventory
#{
#    Log-write $log 'Starting HW inventory'
#    Log-write $log ' Full Inventory =$fullinventory'

#    if ($fullinventory -eq $true)
#    {
#        Log-write $log ' Deleting HW inv calss'
#        Get-WmiObject -namespace root\ccm\invagt  -class InventoryActionStatus -filter "InventoryActionID = '{00000000-0000-0000-0000-000000000001}'" | Remove-WmiObject 
#    }
#    
#    Log-write $log ' Starting HW inv. cycle'

#    Invoke-WMIMethod -Namespace root\ccm -Class SMS_CLIENT -Name TriggerSchedule "{00000000-0000-0000-0000-000000000001}" 
#}


function Get-InstalledApps
{
    Log-write $log 'Start Get-InstalledApps'
    if ([IntPtr]::Size -eq 4) {
        $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
        Log-write $log 'Found x86'
    }
    else {
        $regpath = @(
            'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
            'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
        )
        Log-write $log 'Found x64'
    }
    Get-ItemProperty $regpath | .{process{if($_.DisplayName -and $_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, DisplayVersion, UninstallString |Sort DisplayName
}

Function Log-Write{
  Param ([Parameter(Mandatory=$true)][string]$LogPath, [Parameter(Mandatory=$true)][string]$LineValue) 

   Process{ 
     Add-Content -Path $LogPath -Value $LineValue 
   } 
} 


Log-write $log 'Startinging script'

# If running in x86 mode restart in x64 mode.
# Note: This will will closed the SCCM thread and open a new thread. 
if ($PSHome -match 'syswow')
{
    Log-write $log 'Found syswow'
    Log-write $log 'Shell to x64 version'
    start-process "C:\Windows\sysnative\WindowsPowerShell\v1.0\powershell.exe" -arg "-ExecutionPolicy bypass  -file $e" -Wait
    Log-write $log 'Return from x64 version; exiting'
    exit
}



$result = Get-InstalledApps | where {$_.DisplayName -like $appToMatch}
$result 

Log-write $log 'Found these isntalled apps:'
ForEach ($u in $result) 
{
    $UnInstall = $u.UninstallString 
    $UnInstall = $UnInstall.Trim()

    If ($UnInstall -contains '.msi'){
        Log-write $log "uninstall string, containt an MSI"
        $UnInstall = $UnInstall -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
        $UnInstall = $UnInstall.Trim()
        Log-write $log $UnInstall
        Log-write $log 'Start MSIExec'
        start-process "msiexec.exe" -arg "/X $UnInstall /norestart /quiet /qn /s /l*v $env:TEMP\$UnInstall.log" -Wait
        Log-write $log 'After MSIExec'
    }
    else
    {
        Log-write $log "Uninstall string, containt an EXE"
        $UnInstall = $UnInstall.Trim()
        Log-write $log $UnInstall
        Log-write $log 'Start MSIExec'
        start-process $UnInstall  "/S /V/qn /ms" -Wait
        Log-write $log 'After MSIExec'
    }
} 

#Start-HWInventory
Not Monitored
Not Monitored
Tag not monitored by Microsoft.
41,674 questions
Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
5,609 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Rich Matheisen 47,581 Reputation points
    2022-03-02T15:43:29.067+00:00

    You can use Start-Job to run each uninstall and then wait for the jobs to complete.

    0 comments No comments

  2. Timothy Blunt 0 Reputation points
    2025-01-18T06:44:47.7433333+00:00
    $e=$MyInvocation.InvocationName
    $log=$env:temp+'\PSuninstall.log'
    
    
    
    $unlist = "WinRar","7-Zip","adobe"
    
    
    
    function Get-InstalledApps
    {
        Log-write $log 'Start Get-InstalledApps'
        if ([IntPtr]::Size -eq 4) {
            $regpath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
            Log-write $log 'Found x86'
        }
        else {
            $regpath = @(
                'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*'
                'HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
            )
            Log-write $log 'Found x64'
        }
      $res = Get-ItemProperty $regpath | .{process{if($_.DisplayName -and $_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, DisplayVersion, UninstallString |Sort DisplayName
      return $res
    }
    
    Function Log-Write{
      Param ([Parameter(Mandatory=$true)][string]$LogPath, [Parameter(Mandatory=$true)][string]$LineValue) 
    
       Process{ 
         Add-Content -Path $LogPath -Value $LineValue 
       } 
    } 
    
    function Test-GuidString {
        param(
            [string]$String
        )
        try
        {
        [System.Guid]$parsedGuid = $null 
        return [System.Guid]::TryParse($String, [ref]$parsedGuid)
        }catch{return $false}
    }
    
    
    Log-write $log 'Starting script'
    
    # If running in x86 mode restart in x64 mode.
    # Note: This will will closed the SCCM thread and open a new thread. 
    if ($PSHome -match 'syswow')
    {
        Log-write $log 'Found syswow'
        Log-write $log 'Shell to x64 version'
        start-process "$env:SystemDrive\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -arg "-ExecutionPolicy bypass  -file $e" -Wait
        Log-write $log 'Return from x64 version; exiting'
        exit
    }
    foreach ($item in $unlist) 
    {
        write-host $item
        $appToMatch = @('*' + $item + '*')
        $result = Get-InstalledApps | where {$_.DisplayName -like $appToMatch}
        if ($result -eq $null -or $result -eq ""){return}
    
        Log-write $log 'Found these isntalled apps:'
        ForEach ($u in $result) 
        {
        $UnInstall = $result.UninstallString} 
        write-host $UnInstall
        $UnInstall = $UnInstall.Trim()
    
        If ($UnInstall.Contains("Msi"))
        {
            Log-write $log "uninstall string, containt an MSI"
            $UnInstall = $UnInstall -Replace "msiexec.exe","" -Replace "/I","" -Replace "/X",""
            $UnInstall = $UnInstall.Trim()
            Log-write $log $UnInstall
            Log-write $log 'Start MSIExec'
            try{
            start-process "msiexec.exe" -arg "/X $UnInstall /norestart /qb /l*v $env:TEMP\$UnInstall.log" -Wait
            }catch{}
            Log-write $log 'After MSIExec'
        }
        else
        {
            Log-write $log "Uninstall string, contains an EXE"
            $UnInstall = $UnInstall.Trim()
            Log-write $log $UnInstall
            Log-write $log 'Start MSIExec'
            try{
            start-process $UnInstall  "/S" -Wait
            }catch{}
            Log-write $log 'After MSIExec'
        }
        
        if (Test-GuidString $UnInstall)
        {
         try
         {
         $guid = $UnInstall
         $product = Get-WmiObject -Class Win32_Product | Where-Object {$_.IdentifyingNumber -eq $guid}
         if ($product)
         {
         $product.Uninstall()
         }    
         }catch{}
        }
        
    }
    
    
    
    
     
    
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.