# The ARP DisplayName carries a version suffix ("Logitech Unifying Software 2.52"), # so match on a prefix, plus the publisher to avoid other products sharing it. $softwareName = "Logitech Unifying Software" $softwareNameLike = "$softwareName*" $softwarePublisher = "Logitech" $machineKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*' $machineKey32on64 = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' $exitCode = 0 $timeoutSeconds = 300 # Logs matching entries and their publishers to diagnose a name/publisher miss. function Write-UnifyingCandidates { Write-Host "Registry entries matching '$softwareNameLike':" $found = Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue | ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } | Where-Object { $_.DisplayName -like $softwareNameLike } if (-not $found) { Write-Host " (none)" ; return } foreach ($f in $found) { Write-Host " DisplayName='$($f.DisplayName)' Publisher='$($f.Publisher)' Version='$($f.DisplayVersion)'" } } function Get-UnifyingUninstallKey { Get-ChildItem -Path @($machineKey, $machineKey32on64) -ErrorAction SilentlyContinue | ForEach-Object { Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue } | Where-Object { $_.DisplayName -like $softwareNameLike -and $_.Publisher -eq $softwarePublisher } | Select-Object -First 1 } # Stop leftovers: they hold file locks, and -Wait would block on them. foreach ($name in @("LogiUnify", "Unifying", "UnifyingUnInstaller", "DJCUHost")) { Stop-Process -Name $name -Force -ErrorAction SilentlyContinue } try { $key = Get-UnifyingUninstallKey if (-not $key) { Write-UnifyingCandidates Write-Host "Uninstall entry not found for '$softwareName' with publisher '$softwarePublisher'." Exit 0 } $uninstallString = if ($key.QuietUninstallString) { $key.QuietUninstallString } else { $key.UninstallString } Write-Host "Uninstall string: $uninstallString" # Handles quoted paths, unquoted paths with spaces, and bare tokens. $uninstallCommand = $uninstallString $existingArgs = "" if ($uninstallCommand -match '^\s*"([^"]+)"\s*(.*)$') { $uninstallCommand = $Matches[1]; $existingArgs = $Matches[2] } elseif ($uninstallCommand -match '(?i)^\s*(.+?\.exe)\s*(.*)$') { $uninstallCommand = $Matches[1]; $existingArgs = $Matches[2] } elseif ($uninstallCommand -match '^\s*(\S+)\s*(.*)$') { $uninstallCommand = $Matches[1]; $existingArgs = $Matches[2] } # This vendor NSIS uninstaller rejects the in-place "_?=