You can use Start-Job to run each uninstall and then wait for the jobs to complete.
Massively uninstall applications with PowerShell
Rafael Aguilar
496
Reputation points
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
2 answers
Sort by: Most helpful
-
-
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{} } }