Solved

Powershell - Read registry to determine installed apps

Posted on 2010-08-30
12
1,171 Views
Last Modified: 2012-06-21
I have tried using Win32_Product and it takes about three minutes when ran locally and doesn't run at all for remote systems.  

I would like to read the registry to determine what s/w are installed. I need to be able to have a filter so that it only shows apps that have a display name of "adobe *".

hklm:\software\microsoft\windows\currentversion\uninstall

contains everything I need but I only want some select info for select applications.

Any help would be greatly appreciated.

Thanks,
K
0
Comment
Question by:kabaam
  • 4
  • 4
  • 2
  • +2
12 Comments
 
LVL 65

Expert Comment

by:rockiroads
ID: 33563222
looks like you need to read the registry as a drive then use something like

examples here
http://tfl09.blogspot.com/2007/01/using-registry-with-powershell.html
helper functions http://powershell.com/cs/blogs/tips/archive/2009/11/25/reading-registry-values.aspx
0
 
LVL 11

Author Comment

by:kabaam
ID: 33563444
The first link refers to code that only works on a local machine.  It doesn't do what I need for remote systems
The second link refers to gaining access to exact keys.  That is not what I am trying to do.  I am looking to gain access to an array of keys based on search filter for many computers on a network.

I have attached code snip that does what I want when run from a local box.  I want to do the same for many others from one system

thanks,
C


Clear-Host

clear-variable strcomputer
$colComputers = get-content "c:\powershell\outputFiles\Clients.txt" 

foreach ($strComputer in $colComputer)
    {
    write-host $strcomputer -foreground "green"

    $Programs = $RegLoc | foreach-object {Get-ItemProperty $_.PsPath}
    $RegLoc = Get-ChildItem HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall #-computername $strComputer
    Foreach ($name in $Programs | sort-Object DisplayName) `
        {
        if ($name.displayname -match "adobe")
        {
        Write-Host $name.Displayname -nonewline 
        Write-Host $name.DisplayVersion        
        }

}

}

Open in new window

0
 
LVL 6

Expert Comment

by:r3nder
ID: 33563935
This provides you with a rough list of installed programs:


Dir hklm:\software\microsoft\windows\currentversion\uninstall |   ForEach-Object { Write-Host -ForegroundColor Yellow "Installed Products:" 

}

{

    $values = Get-ItemProperty $_.PSPath;     "{0:-30} {1:20}" -f $values.DisplayName, $values.MoreInfoURL  

}

{

Write-Host -ForegroundColor Yellow "Finished!"

}

Open in new window

0
 
LVL 70

Assisted Solution

by:Chris Dent
Chris Dent earned 450 total points
ID: 33565500

>  ... Win32_Product ...

Yeah, you should avoid that class, it's pure evil. For a start it's slow, and then it causes every installed MSI to re-configure (because that's how it enumerates the list). Check out the Event Log on the target machine after you run it.

For the registry you have two choices:

WMI: Win32_Registry and StdRegProv
.NET: Microsoft.Win32.Registry*

The first has the advantage that it allows you to authenticate within your code. The second does not, but is easier to work with.

Any preference?

Chris
0
 
LVL 11

Author Comment

by:kabaam
ID: 33567610
Thanks Chris and R3nder,

I have to step out of office for a few days so my testing and access will be limited but I will do what I can to ensure this question doesn't stay open too long.

The scripts I, including this one, will be done by a user or users that are local admins on all boxes so passing specific credentials would not be required.

Thanks,
C
0
 
LVL 70

Accepted Solution

by:
Chris Dent earned 450 total points
ID: 33568153

Using .NET from an arbitrary computer name, administrative rights are assumed. Wasn't sure which values you wanted :)

Chris
$Computer = "computer"

$BaseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $Computer)
$UninstallKey = $BaseKey.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall")

$UninstallKey.GetSubKeyNames() | ForEach-Object { 
  $UninstallKey.OpenSubKey($_) | 
    Where-Object { $_.GetValue("DisplayName") } |
    Select-Object `
      @{n='Name';e={ $_.GetValue("DisplayName") }},
      @{n='DisplayVersion';e={ $_.GetValue("DisplayVersion") }},
      @{n='InstallDate';e={ $_.GetValue("InstallDate") }},
      @{n='Publisher';e={ $_.GetValue("Publisher") }}
}

Open in new window

0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 70

Expert Comment

by:Chris Dent
ID: 33568677

Upgraded the snippet a little bit.

Chris
Function Get-InstalledSoftware {
  <#
    .Synopsis
      Enumerates the Uninstall registry key to display installed software
    .Description
      Enumerates the Uninstall registry key to display installed software. This function assumes the caller is authenticated.
    .Parameter ComputerName
      The computer to execute against. Defaults to local machine.
  #>
  
  [CmdLetBinding()]
  Param(
    $ComputerName = $Env:ComputerName
  )

  Try {
    $BaseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $ComputerName)
  } Catch { }
  If ($?) {
    $UninstallKey = $BaseKey.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Uninstall")

    $UninstallKey.GetSubKeyNames() | ForEach-Object { 
      $UninstallKey.OpenSubKey($_) | 
        Where-Object { $_.GetValue("DisplayName") } |
        Select-Object `
          @{n='Name';e={ $_.GetValue("DisplayName") }},
          @{n='DisplayVersion';e={ $_.GetValue("DisplayVersion") }},
          @{n='InstallDate';e={
            $DateString = $_.GetValue("InstallDate")
            If ($DateString) {
              [DateTime]$DateTime = "01/01/1601"
               If ([DateTime]::TryParse($DateString, [Ref]$DateTime)) {
                $DateTime
              } Else {
                [DateTime]::ParseExact($DateString, "yyyyMMdd", $Null)
              }
            } }},
          @{n='Publisher';e={ $_.GetValue("Publisher") }}
    }
  }
}

Open in new window

0
 
LVL 65

Assisted Solution

by:rockiroads
rockiroads earned 50 total points
ID: 33571296
Just managed to get powershell installed, damn thing wouldn't install so ended up using the reghack to get it to install.

Anyways was reading up on this and came across WMI which can be used instead of accessing the registry directly.
Example can be found here http://www.techmumbojumblog.com/?p=39

And just going through all the posts here since I noticed Chris has already mentioned this (sorry Chris, I should of read the posts before I was trying to get my powershell going). And Chris has given reasons why win32 isn't all that. But I posted that link anyways since I thought it might be useful to someone who may want to use Win32. Part 2 of that blog though has the registry way.
0
 
LVL 11

Author Comment

by:kabaam
ID: 33572698
Thanks again Chris.  I do not have much time to work with this but I did a quick test.  The first version works great and I can work with it.  The second runs without error but yields empty.  no Results (on Win7).
I will try to get more time with it later.

Thanks again.
0
 
LVL 70

Expert Comment

by:Chris Dent
ID: 33574299

The second is only the function, it still needs calling, or did you do that? :)

e.g.

Get-InstalledSoftware "SomeComputer"

If you don't specify a computer it will default to the local machine.

Chris
0
 
LVL 11

Author Comment

by:kabaam
ID: 33577143
Ahh that makes sense.  Thanks,

for what I need these are both outstanding options.   I am upping the points because you had more work to do on this one.

Thanks again,
K
0
 
LVL 13

Expert Comment

by:soostibi
ID: 33578207
Overtime solution with PowerShell remoting:
Clear-Host  

  

$colComputers = get-content "c:\powershell\outputFiles\Clients.txt"   



$script = {

    $regloc = get-item hklm:\software\microsoft\windows\currentversion\uninstall

    write-host $env:computername -foreground "green"  

  

    $RegLoc | get-childitem | 

        Get-ItemProperty | sort-Object DisplayName | 

            Where-Object {$_.pschildname -match "adobe"} | 

                ft displayname, displayversion -HideTableHeaders

}



Invoke-Command -ComputerName $colComputers -ScriptBlock $script

Open in new window

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Hi all.   The other day I had to change the passwords for a bunch of users on the fly. Because they were so many, I decided to do it in an automated way and I would like to share it with you all.   If you are not doing it directly in a Domain Co…
Synchronize a new Active Directory domain with an existing Office 365 tenant
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now