Uninstall Sofware using registry key

This topic contains 12 replies, has 6 voices, and was last updated by Profile photo of m magnan m magnan 1 year, 8 months ago.

  • Author
    Posts
  • #22768
    Profile photo of Marc
    Marc
    Participant

    I am trying to build something to uninstall APC Powerchute Network Shutdown. I need to do a few things here:

    1 – Go through AD and find the machines (Done)
    (Get-ADComputer -SearchBase "OU=Servers,DC=domain=ca" -filter *).name

    2 – Get the registry value (Done)
    Get-RegString -Key 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\powerchute network Shutdown' -Value UninstallString

    3 – Now I need to uninstall using the uninstall key but the problem is that I can't figure out how to pass all this through

    Any ideas?

    Here is what I have:

    Get-QADComputer -Searchroot "OU=Servers,DC=DOMAIN,DC=ca"| ForEach-Object {
    [PSCustomObject] @{
    Servername = $_.name
    online = Test-Connection $_.name -Count 1 -Quiet
    }
    } | Export-Csv -Path c:\Results.csv -NoTypeInformation
    # selecting only computers online | where {$_.name online}

    | Foreach-Object{
    Get-RegString -Key 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\powerchute network Shutdown' -Value UninstallString
    }

  • #22770
    Profile photo of Tim Pringle
    Tim Pringle
    Participant

    Hey Marc,

    If I understand right, you're wanting to do remote uninstalls?

    In case you might come across some systems that do not have the software installed, or have for whatever reason a slightly different uninstall cmd, it's probably best to do the reading of the registry key within the remote scriptblock. Based on whether or not you get a result from trying to read this key, you can then carry out the rest of the script for uninstalling.

    Here's a rough guide to the type of thing I think you'd need to do. The cmd /c $uninstallCMD should allow you to execute the command without the need for parsing the arguments. Bear in mind that when you run this, the remote session will be frozen until the uninstallation ends. I've not checked the code entirely, so you may need to do a couple of changes.

    Get-QADComputer -Searchroot 'OU=Servers,DC=DOMAIN,DC=ca'|
    ForEach-Object -Process {
        [PSCustomObject] @{
            Servername = $_.name
            online     = Test-Connection -ComputerName $_.name -Count 1 -Quiet
        }
    } |
    Export-Csv -Path c:\Results.csv -NoTypeInformation
    
    
    $Results = Import-Csv -Path c:\Results.csv | Where-Object -FilterScript {
        $_.name -eq 'online'
    }
    
    #Let's start doing the remote uninstalls
    
    ForEach ($computername in $Results.servername) 
    {
        Invoke-Command -ComputerName $computername -ScriptBlock {
            $ErrorAction = 'Stop'
            Try 
            {
                $UninstallCMD = Get-RegString -Key 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\powerchute network Shutdown' -Value UninstallString
            }
            Catch 
            {
    
            }
            If ($UninstallCMD) 
            {
                cmd.exe /c $UninstallCMD
            }
        }
    }
    
  • #22869
    Profile photo of m magnan
    m magnan
    Participant

    Thanks Tim, you are correct I am trying to setup a remote uninstall for software that does not show up in Add/Remove programs so I need to get the uninstall string from the registry and use that string to uninstall the software.

    I have worked with your suggestions and it seems to work fine for single machines. When I try to pipe in the Active Directory machines from the Get-QADComputer command I see to be losing the computer name in the test-connection part. Below is the error. Can you see why I would be losing that? Thanks in advance for your help.


    Test-Connection : Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument that is not null or empty and then try
    the command again.
    At line:10 char:52
    + online = Test-Connection -ComputerName $_.name -Count 1 -Quiet
    + ~~~~~~~
    + CategoryInfo : InvalidData: (:) [Test-Connection], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.TestConnectionCommand

  • #22870
    Profile photo of m magnan
    m magnan
    Participant

    Actually Tim, I must have had a typo. The Test-Connection does work. I will test the remainder and let you know how it goes. Thanks!

  • #22882
    Profile photo of m magnan
    m magnan
    Participant

    I have a functioning script now that seems to work as expected. Thanks for your valuable input!!

    I have added a few pieces and removed the PSremoteRegistry commands because I was having trouble with it.

    I don't have anything output or logging after the $uninstallcmd. So one more thing that would be nice to add would be another output file that will possibly give me the info from $uninstallcmd

    I tried a pipe but was getting nothing. Maybe you can help with that?


    add-pssnapin quest.activeroles.admanagement
    $Application = "Powerchute network shutdown"

    Get-QADComputer -Searchroot 'OU=Servers,DC=domain=ca'|
    ForEach-Object -Process {
    [PSCustomObject] @{
    Servername = $_.name
    online = Test-Connection -ComputerName $_.name -Count 1 -Quiet
    }
    } |
    Export-Csv -Path c:\Results.csv -NoTypeInformation

    $Results = Import-Csv -Path c:\Results.csv | Where-Object -FilterScript {
    $_.name -eq 'online'
    }

    #Let's start doing the remote uninstalls

    ForEach ($computername in $Results.servername)
    {
    Invoke-Command -ComputerName $computername -ScriptBlock {
    $ErrorAction = 'Stop'
    Try
    {

    $UninstallCMD = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
    Get-ItemProperty | Where-Object {$_.DisplayName -eq $Application } | Select -ExpandProperty UninstallString
    }
    Catch
    {

    }
    If ($UninstallCMD) {

    cmd.exe /c $UninstallCMD -q
    }
    }
    }

  • #22898
    Profile photo of m magnan
    m magnan
    Participant

    Hi Tim,

    It seems like when I run the entire script against the target machines from the CSV file, nothing happens. I don't have any errors but the program doesn't get uninstalled. Can we insert some logging to see what's happening?

    Thanks
    Marc

  • #22903
    Profile photo of Tim Pringle
    Tim Pringle
    Participant

    Hi Marc,

    I think it'll be because you refer to $application within your scriptblock, when it's defined outside of it.

    A scriptblock does not have visibility of variables outside of it unless you pass them in as arguments, or alternatively refer to them via $using:variablename.

    Try changing the line to

    Get-ItemProperty | Where-Object {$_.DisplayName -eq [b]$Using:Application[/b] } | Select -ExpandProperty UninstallString
    
  • #23164
    Profile photo of m magnan
    m magnan
    Participant

    Hi Tim, the $USING is new to me. I have tried it remotely and get nothing. I tried running it locally and get the following error since it can't be run against local machines.

    PS C:\windows> Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
    >> Get-ItemProperty |
    >> Where-Object {$_.DisplayName -eq $Using:Application} |
    >> Select-Object -Property UninstallString
    >>
    A Using variable cannot be retrieved. A Using variable can be used only with
    Invoke-Command, Start-Job, or InlineScript in the script workflow. When it is
    used with Invoke-Command, the Using variable is valid only if the script block
    is invoked on a remote computer.
    At line:3 char:23
    + Where-Object {$_.DisplayName -eq $Using:Application} |
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : UsingWithoutInvokeCommand

  • #23170
    Profile photo of Daniël
    Daniël
    Participant

    I think the error is within your Import-CSV filterscript. You're filtering based on 'name' equals 'online'. But the CSV only contains the property 'servername' (not name) and the property online with a boolean True or False.

    This would fix that:

    $Results = Import-Csv -Path C:\Results.csv | Where-Object -FilterScript {
    $_.Online -eq $True
    }
    
  • #23195
    Profile photo of m magnan
    m magnan
    Participant

    Thanks, I will test the Import-CSV filterscript as you mentioned. I have been testing and I see another potential issue. When I run the individual pieces, I see that the Uninstall string is "...\Program files\APC\Powerchute\uninstall.exe"

    The $uninstallCMD properly holds the value but there is a space in "...\Program Files" so the uninstall command fails. I think I need to store the Uninstall Command where spaces will be tolerated.

    I can't figure out how to get that value and store it with spaces. I have tried various usage of "quotation marks", 'back ticks'.

    The term 'C:\Program' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct
    + CategoryInfo : ObjectNotFound: (C:\Program:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
    + PSComputerName : MARCW2K12

    Any ideas on this would be great!

    Thanks
    Marc

  • #23437
    Profile photo of Andrew Pearce
    Andrew Pearce
    Participant

    I have a function that handles my uninstalls – they're 'locally' called rather than remotely, however for non msiexec.exe uninstall commands, I have the following code blocks. I don't know if this will help in your instance, but just in case...

    # Remove double quotes from string
    $UninstallCmd = $UninstallCmd -replace '"'
    
    # String up to and including the .exe
    $UninstallExecutible = $UninstallCmd.substring(0,$UninstallCmd.IndexOf(".exe") +4 )
    
    # Any parts after the .exe		
    $UninstallArguments = $UninstallCmd.substring($UninstallCmd.IndexOf(".exe") +4 )
    

    Then the uninstall is handled with:

    $RetVal = Start-Process -FilePath "$UninstallExecutible" -ArgumentList "$UninstallArguments" -Wait -Passthru
    
  • #23441
    Profile photo of Venugopal
    Venugopal
    Participant

    Hello Guys,

    My version of it.. if it helps..

    #Checking for Installation.
     $check = (Get-ItemProperty -path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{xxxxx-xx-x-x-x-x--xxx-x-x}}_is1' -ErrorAction SilentlyContinue | select-object -ExpandProperty "DisplayName" | findstr "xxxxxx")
    
      if( $check -like '*xxx*')
     {
        Write-Output "$check available"
        Stop-Service -Name XXXXXXX # if any service dependednt.
        $checks_uninstall = (Get-ItemProperty -path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{xxxx-x-x-x-x-x-xxxx-x-x-x-x-x-x}}_is1' | select-object -ExpandProperty "QuietUninstallString")
        if($checks_uninstall -eq '')
        {
            Write-Output "Uninstallation Failed!"
        }
        else
        {
            $checks_uninstall = $checks_uninstall -replace '"',''
            $scriptBlock = [Scriptblock]::Create($checks_uninstall)
            Invoke-Command -ScriptBlock $scriptBlock
            Write-Output "Uninstallation Completed! "
        }
    
     }
    
    

    hope it helps!

    Regards,
    V.

  • #23467
    Profile photo of m magnan
    m magnan
    Participant

    Thank you very much for all this great feedback! As this was getting too complicated and taking too much time to figure out with Powershell I decided to go with a .bat file to uninstall and applied it through a group policy at start up. Really simple and gets the job done. If anyone is interested the code is below.

    REM Perform clean uninstall of Powerchute Netwok Shutdown
     echo Perform clean uninstall of Powerchute Netwok Shutdown
     if exist "C:\Program Files\APC\PowerChute\uninstall.exe" "C:\Program Files\APC\PowerChute\uninstall.exe" -q
     if exist "D:\Program Files\APC\PowerChute\uninstall.exe" "D:\Program Files\APC\PowerChute\uninstall.exe" -q
     if exist "E:\Program Files\APC\PowerChute\uninstall.exe" "E:\Program Files\APC\PowerChute\uninstall.exe" -q
     echo Removal Successful
    
    
    
    		
    	

You must be logged in to reply to this topic.