none
How to find installed software and collect some properties RRS feed

  • Question

  • Hi,

    I am trying to use PowerShell to find out if a software title is in the registry using the following paths:

    "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
    "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"

    I have been using this to find software and it seems to work reliably:

    Get-ItemProperty $uninstallPath\* | where {$_.DisplayName -eq $softwareTitle}

    Depending on the installer that was used, the software I am looking for will either have a GUID (or not) but I still need to locate it in the registry and gather some properties.

    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{23170F69-40C1-2702-1900-000001000000} OR
    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\7-Zip

    Once I have determined the software is installed, how do I collect a few properties in the registry related to the software such as:

    DisplayName
    DisplayVersion
    UninstallString

    I have seen several examples on this topic throughout the forums but they usually ask for a full list of all software installed or to find out if one software title is installed. I have not found any examples of gathering any properties though.

    Thank you!

    Rob



    • Edited by robwm1 Thursday, August 1, 2019 4:18 PM
    Thursday, August 1, 2019 4:17 PM

Answers

  • For clarity this would be my preferred method:

    $paths = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
             'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    $props = @(
        @{n='Architecture';
          e={
                if($_.PsParentPath -match 'SysWow'){
                    '32-bit'
                }else{
                    '64-bit'
                }
            }
        },
        'Publisher',
        'Version',
        'DisplayName',
        'UninstallString'
    )
    Get-ItemProperty $paths | Select-Object $props
    
    

    It is also easier to change and debug.


    \_(ツ)_/

    • Marked as answer by robwm1 Thursday, August 1, 2019 5:44 PM
    Thursday, August 1, 2019 5:19 PM

All replies

  • Please look in the Gallery for scripts that do what you ask. There are a few.


    \_(ツ)_/

    Thursday, August 1, 2019 4:57 PM
  • This is how to retrieve registry properties from multiple keys:

    $paths = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
             'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    Get-ItemProperty $paths | select Publisher, Version, DisplayName, UninstallString


    \_(ツ)_/

    Thursday, August 1, 2019 5:01 PM
  • Here's one way:


    $paths = @(
      "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
      "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    )
    foreach ( $path in $paths ) {
      if ( $path -match "WOW6432Node" ) {
        $arch = "32-bit"
      }
      else {
        $arch = "64-bit"
      }
      Get-ChildItem $path | Select-Object -ExpandProperty Name | ForEach-Object {
        $path = $_
        Get-ItemProperty ($path -replace '^HKEY_LOCAL_MACHINE\\','HKLM:\') | Select-Object `
          @{Name = "Architecture"; Expression = {$arch}},
          @{Name = "Path";         Expression = {$path}},
          DisplayName,DisplayVersion,InstallDate,UninstallString
      }
    }
    


    -- Bill Stewart [Bill_Stewart]

    Thursday, August 1, 2019 5:09 PM
    Moderator
  • An easier way to get architecture.

    $paths = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
             'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    Get-ItemProperty $paths | 
        select @{n='Architecture';e={if($_.PsParentPath -match 'SysWow'){'32-bit'}else{'64-bit'}}},Publisher, Version, DisplayName, UninstallString


    \_(ツ)_/


    • Edited by jrv Thursday, August 1, 2019 5:15 PM
    Thursday, August 1, 2019 5:15 PM
  • For clarity this would be my preferred method:

    $paths = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
             'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    $props = @(
        @{n='Architecture';
          e={
                if($_.PsParentPath -match 'SysWow'){
                    '32-bit'
                }else{
                    '64-bit'
                }
            }
        },
        'Publisher',
        'Version',
        'DisplayName',
        'UninstallString'
    )
    Get-ItemProperty $paths | Select-Object $props
    
    

    It is also easier to change and debug.


    \_(ツ)_/

    • Marked as answer by robwm1 Thursday, August 1, 2019 5:44 PM
    Thursday, August 1, 2019 5:19 PM
  • jrv,

    I tweaked your example slightly and I can pull up the software I am looking for. In your code, the software was presented in a list but after I added to the pipeline, the results are in table format which probably doesn't matter.

    $softwareTitle = "7-Zip"
    $paths = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
             'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    $props = @(
        @{n='Architecture';
          e={
                if($_.PsParentPath -match 'SysWow'){
                    '32-bit'
                }else{
                    '64-bit'
                }
            }
        },
        'DisplayName',
        'DisplayVersion',
        'UninstallString'
    )
    Get-ItemProperty $paths | where {$_.DisplayName -match $softwareTitle} | Select-Object $props

    How do I get the properties into variables for further analysis? Depending on the version I find and where it was in the registry, it will require a different command line. So it will be important to hold those values in variables so I can do some decision making with them.

    I should mention that the ultimate goal is to remove any 7-Zip version lower than v19.00 and then install 19.00.

    Thank you,

    Rob


    • Edited by robwm1 Thursday, August 1, 2019 5:37 PM
    Thursday, August 1, 2019 5:35 PM
  • Just assign the output to a variable.

    $product = Get-ItemProperty$paths | where {$_.DisplayName -match $softwareTitle} | Select-Object$props
    $product.DisplayName
    … etc


    \_(ツ)_/


    • Edited by jrv Thursday, August 1, 2019 5:40 PM
    Thursday, August 1, 2019 5:39 PM
  • Thank you very much for your guidance as always! I need to write scripts more often...

    Would you be able to recommend any reading to better understand your usage of $props = @() ? I have never seen anything like this before so it would be great to wrap my head around this.

    Thursday, August 1, 2019 5:48 PM
  • Thank you very much for your guidance as always! I need to write scripts more often...

    Would you be able to recommend any reading to better understand your usage of $props = @() ? I have never seen anything like this before so it would be great to wrap my head around this.

    For all Cmdlets read the help carefully. Many parameters allow an array of vaues. Many time we can use computed values. "Select-Object" has examples.

    The most important thing is to learn basic PowerShell from a known good source and not from copying code, guessing or listening to other untrained users.  All of this will just confuse a very simple system that has to be learned from the ground up.

    All tech ology is empirical and requires learning it in a correct order from  first principles to more complex concepts.  Steps cannot be skipped or ignored.

    If you want to be a brain surgeon you must first learn biology.  There is no way around this rule.

    Here is one place to start although I recommend a good book more.

    Simply stated - a computed property is a hash with a very specific schema that the PowerShell engine recognizes and executes.  It has a name and a script block to execute.  The script block can contain any code needed within reason.


    \_(ツ)_/

    Thursday, August 1, 2019 6:03 PM
  • jrv,

    I really appreciate you taking the time to share this! I will definitely spend more time reading up on your links and anything else I can get my hands on. I agree, trying to gather other people's examples and put them together in a meaningful way is not helpful when you don't really understand what is happening.

    -Rob

    Thursday, August 1, 2019 6:13 PM
  • I ran into an issue where I have computers that may have used both an EXE and MSI installers for different versions. This will show more than one instance installed in Apps & Features. In this case, I am thinking I would need to capture each instance of 7-Zip found in the registry as an object. Then I would need to step through each object to run the uninstall string to ensure all instances are fully removed.

    I was looking at videos and documentation most of the day yesterday and I haven't found a good example of an approach to expand upon your snippet to capture all cases and then step through to uninstall every instance.

    Is there a good resource that might discuss a scenario like this?

    Friday, August 2, 2019 3:14 PM
  • I ran into an issue where I have computers that may have used both an EXE and MSI installers for different versions. This will show more than one instance installed in Apps & Features. In this case, I am thinking I would need to capture each instance of 7-Zip found in the registry as an object. Then I would need to step through each object to run the uninstall string to ensure all instances are fully removed.

    I was looking at videos and documentation most of the day yesterday and I haven't found a good example of an approach to expand upon your snippet to capture all cases and then step through to uninstall every instance.

    Is there a good resource that might discuss a scenario like this?

    No. This is something that is not documented in any one place.

    MSI installers use the registry key whether they are EXE or MSI types.  An EXE installed MSI calls the EXE a bootstrap that is used to decompress the MSI and support files. 

    Some third party installs do not log to the registry and may use what is called an XCOPY install meaning that there are no registry dependencies and all components are installed in a single folder set.  These can be removed by deleting the folders but shortcuts and start menu links would need to be discovered. Some of these may have a removals tool. This is up to the individual vendor and cannot be discovered in Windows.

    7-Zip has always been distributed as XCOPY and MSI install depending on who is doing the distribution. You will have to know what you have.

    One reason companies do not allow public domain or open source software is that it cannot be automatically removed by normal means.  Many commercial management tools can manage some of the most popular open source software but they maintain databases of methods.

    Other issues are the web based click-to-install apps which are not registered in the system and may have an uninstaller included or may have  GUI only removal mechanism.   Of course there are also "Store" apps which are installed per-user so any removal would have to be done per-user.

    And it goes on.  My recommendation is that no software should be installed until the removal method has been defined and documented.  A software standards group would then need to determine if the product can be used correctly within the organization.  Home and independent users should also follow the same steps.


    \_(ツ)_/

    Friday, August 2, 2019 3:34 PM
  • I should also note that 7-Zip and other software can be installed as both 32 bit and 64 bit on 64 bit architectures.  Two uninstallers will be present when both are installed.  I don't know if the 7-Zip guys have learned how to create a 64 bit version that works in a 32 bit session so it is possible that both will be installed.  Check the architecture results.


    \_(ツ)_/

    Friday, August 2, 2019 3:38 PM