list-uninstall-keys.ps1
<#PSScriptInfo
.VERSION 1.0.0 .GUID c693116d-5ab5-4985-9408-f2c0bc7ba499 .AUTHOR AndrewTaylor .DESCRIPTION Lists uninstall keys for all items installed. Can export or display in a grid-view output .COMPANYNAME .COPYRIGHT GPL .TAGS intune endpoint MEM environment .LICENSEURI https://github.com/andrew-s-taylor/public/blob/main/LICENSE .PROJECTURI https://github.com/andrew-s-taylor/public .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .SYNOPSIS Lists all uninstall keys for installed software .DESCRIPTION Lists uninstall keys for all items installed. Can export or display in a grid-view output .INPUTS None .OUTPUTS Creates a log file in %Temp% .NOTES Version: 1.0.0 Author: Andrew Taylor Twitter: @AndrewTaylor_2 WWW: andrewstaylor.com Creation Date: 27/09/2023 Purpose/Change: Initial script development .EXAMPLE N/A #> write-host "Checking 32-bit Registry" ##Search for 32-bit versions and list them $allstring = @() $path1 = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" #Loop Through the apps if name has Adobe and NOT reader $32apps = Get-ChildItem -Path $path1 | Get-ItemProperty | Select-Object -Property DisplayName, UninstallString foreach ($32app in $32apps) { #Get uninstall string $string1 = $32app.uninstallstring #Check if it's an MSI install if ($string1 -match "^msiexec*") { #MSI install, replace the I with an X and make it quiet $string2 = $string1 + " /quiet /norestart" $string2 = $string2 -replace "/I", "/X " #Remove msiexec as we need to split for the uninstall $string2 = $string2 -replace "msiexec.exe", "" #Create custom object with name and string $allstring += New-Object -TypeName PSObject -Property @{ Name = $32app.DisplayName String = $string2 } } else { #Exe installer, run straight path $string2 = $string1 $allstring += New-Object -TypeName PSObject -Property @{ Name = $32app.DisplayName String = $string2 } } } write-host "32-bit check complete" write-host "Checking 64-bit registry" ##Search for 64-bit versions and list them $path2 = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" #Loop Through the apps if name has Adobe and NOT reader $64apps = Get-ChildItem -Path $path2 | Get-ItemProperty | Select-Object -Property DisplayName, UninstallString foreach ($64app in $64apps) { #Get uninstall string $string1 = $64app.uninstallstring #Check if it's an MSI install if ($string1 -match "^msiexec*") { #MSI install, replace the I with an X and make it quiet $string2 = $string1 + " /quiet /norestart" $string2 = $string2 -replace "/I", "/X " #Remove msiexec as we need to split for the uninstall $string2 = $string2 -replace "msiexec.exe", "" #Uninstall with string2 params $allstring += New-Object -TypeName PSObject -Property @{ Name = $64app.DisplayName String = $string2 } } else { #Exe installer, run straight path $string2 = $string1 $allstring += New-Object -TypeName PSObject -Property @{ Name = $64app.DisplayName String = $string2 } } } write-host "64-bit checks complete" Add-Type -AssemblyName System.Windows.Forms $form = New-Object System.Windows.Forms.Form $form.Text = "Export or View" $form.Width = 300 $form.Height = 150 $form.StartPosition = "CenterScreen" $label = New-Object System.Windows.Forms.Label $label.Text = "Select an option:" $label.Location = New-Object System.Drawing.Point(10, 20) $label.AutoSize = $true $form.Controls.Add($label) $exportButton = New-Object System.Windows.Forms.Button $exportButton.Text = "Export" $exportButton.Location = New-Object System.Drawing.Point(100, 60) $exportButton.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.AcceptButton = $exportButton $form.Controls.Add($exportButton) $viewButton = New-Object System.Windows.Forms.Button $viewButton.Text = "View" $viewButton.Location = New-Object System.Drawing.Point(180, 60) $viewButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $viewButton $form.Controls.Add($viewButton) $result = $form.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { # Export code here ##Now save the output write-host "Saving output to CSV" ##Prompt for save location $SaveTo = Get-FileName -InitialDirectory $env:UserProfile ##Save it $allstring | Export-Csv -Path $SaveTo -NoTypeInformation write-host "Save Completed to $SaveTo" } elseif ($result -eq [System.Windows.Forms.DialogResult]::Cancel) { # View code here $selected = $allstring | Out-GridView -PassThru -Title "Select object to add string to copy buffer" $selected.string | clip write-host "Copied to clipboard" } |