Solved

Powershell - Read registry to determine installed apps

Posted on 2010-08-30
12
1,179 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
Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

 
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
 
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

Is Your AD Toolbox Looking More Like a Toybox?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The article will show you how you can maintain a simple logfile of all Startup and Shutdown events on Windows servers and desktops with PowerShell. The script can be easily adapted into doing more like gracefully silencing/updating your monitoring s…
Synchronize a new Active Directory domain with an existing Office 365 tenant
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

823 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