0

I am attampting to create a script to uninstall unwanted instances (or old ones) of software that we use on our workstations. I can't seem to get the filtering right, though.

function Get-InstalledSoftware2 {
    [OutputType([System.Management.Automation.PSObject])]
    [CmdletBinding()]
    param (
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Name , [string] $OurName
    )

    $UninstallKeys = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall", "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    $null = New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS
    $UninstallKeys += Get-ChildItem HKU: -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'S-\d-\d+-(\d+-){1,14}\d+$' } | ForEach-Object { "HKU:\$($_.PSChildName)\Software\Microsoft\Windows\CurrentVersion\Uninstall" }
    if (-not $UninstallKeys) {
        Write-Verbose -Message 'No software registry keys found'
    } else {
        foreach ($UninstallKey in $UninstallKeys) {
#            if (!$PSBoundParameters.ContainsKey('OurName')) {
            if ($PSBoundParameters.ContainsKey('Name')) {
                $WhereBlock = { ($_.PSChildName -match '^{[A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12}}$') -and ($_.GetValue('DisplayName') -like "$Name*") }
            } else {
                $WhereBlock = { ($_.PSChildName -match '^{[A-Z0-9]{8}-([A-Z0-9]{4}-){3}[A-Z0-9]{12}}$') -and ($_.GetValue('DisplayName')) }
            }
            $gciParams = @{
                Path        = $UninstallKey
                ErrorAction = 'SilentlyContinue'
            }
            $selectProperties = @(
                @{n='GUID'; e={$_.PSChildName}}, 
                @{n='Name'; e={$_.GetValue('DisplayName')}}
            )
            Get-ChildItem @gciParams | Where $WhereBlock | Select-Object -Property $selectProperties
#            msiexec /x 'GUID' /qn /norestart
        }
    }
}
# }

Get-InstalledSoftware2 -Name 'ScreenConnect' -OurName 'ScreenConnect Client (b3d049b2cd879dd9)'

with the commands commented out, I get the following output:

GUID                                   Name                                   
----                                   ----                                   
{80E0C92B-A22E-4CCA-BB15-E7F8CAE95A96} ScreenConnect                          
{B92DB068-8FAF-4F4E-8ECC-13FF34DA74A5} ScreenConnect Client (b3d049b2cd879dd9)

But if I remove the hashes on the If statement, I get 0 output. Shouldn't I get the 1st result?

GUID                                   Name                                   
----                                   ----                                   
{80E0C92B-A22E-4CCA-BB15-E7F8CAE95A96} ScreenConnect                          

Thanks, everyone!

-Dave

David Peck
  • 27
  • 1
  • 9
  • 1
    What specifically are you removing that is causing an issue. I am having a hard time figuring out what _the hashes on the If statement_ means – Matt Jul 05 '18 at 18:41
  • There are 3 lines commented out: # if (!$PSBoundParameters.ContainsKey('OurName')) { # msiexec /x 'GUID' /qn /norestart # } If I take the hash away on the 1st and 3rd, it adds an if statement to the loop. – David Peck Jul 05 '18 at 18:47
  • I read hashes as hashtable. If you said uncomment that would have be clearer for _me_. I also glaze over comments in code so I was a little lost. Thanks for the clarification. – Matt Jul 05 '18 at 19:19

1 Answers1

0

Your code looks a bit overly complicated.

It's perhaps easier just to use this to get a list of installed software on a computer:

$Software = Invoke-Command -Computer $Computer -ScriptBlock {Get-CimInstance -ClassName Win32_Product}

From there you can view identifying numbers, etc. It also shows where the local msi is saved to.

$Software | Select-Object Name,IdentifyingNumber,LocalPackage

So an example function could be

    param(
       [Parameter(Mandatory=$true)]
       [string[]]$Name
    )

    ForEach ($x in $Name) { 
        [array]$RemoveIDs += Get-CimInstance -ClassName Win32_Product | 
                             Where-Object {$_.Name -match $x}
    }      

    $RemoveIDs | ForEach-Object {
        Sleep 10
        $msi=$_.LocalPackage
        #$msi=$_.IdentifyingNumber
        & msiexec /x $msi /qn
    } 
ErikW
  • 386
  • 2
  • 11
  • My code is probably over-complicated because this is my first real jump into PowerShell. This answer looks really cool, but I have no idea how to apply it to my needs. – David Peck Jul 05 '18 at 21:32
  • copy paste into Powershell ISE, save as Uninstall.ps1 for example. then on target machine, you run .\Uninstall.ps1 -Name 'Firefox','Silverlight' – ErikW Jul 05 '18 at 22:02
  • if you want to invoke on remote machines, there's a few additional lines.... but that starts to get out of scope. There's a great video series on CBTNuggets for Powershell if you want to learn more. – ErikW Jul 05 '18 at 22:06
  • Copy both "$Software" lines as well? – David Peck Jul 05 '18 at 22:07
  • No, just the large block at the bottom. The first two lines are example commands you can run in a powershell command prompt to see results. also, test the code in a virtual machine or a non-important computer first – ErikW Jul 05 '18 at 22:18