Get-RemoteProgram Get list of installed programs on remote or local computer

This script generates a list by querying the registry and returning the installed programs of a local or remote computer. It allows for retrieval of additional properties such as the uninstall string of an application as well.

4.4 Star
100,259 times
Add to favorites
Operating System
E-mail Twitter Digg Facebook
Sign in to ask a question

  • Dot source problem
    5 Posts | Last post April 08, 2016
    • Hello and thank you for sharing that script.
      I am having a problem when trying to dot it and the adjust the parameters to check a list of servers (domain members)
      So i execute the script in the same path the list of servers exist but i get this error.
      PS Version is 3.o
      I am running this in a WS2012 machine
      Thank you in advance
      PS C:\users\Kostas\Desktop\wlpm> . .\Get-RemoteProgram.ps1
      Get-Content -Path C:\Users\Kostas\Desktop\WLPM\serverlist.txt | Get-RemoteProgram
      Function : The term 'Function' 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 and try again.
      At C:\users\Kostas\Desktop\wlpm\Get-RemoteProgram.ps1:1 char:1
      + Function Get-RemoteProgram {
      + ~~~~~~~~~
          + CategoryInfo          : ObjectNotFound: (Function:String) [], CommandNotFoundException
          + FullyQualifiedErrorId : CommandNotFoundException
      Get-RemoteProgram : The term 'Get-RemoteProgram' 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 and try again.
      At line:2 char:66
      + Get-Content -Path C:\Users\Kostas\Desktop\WLPM\serverlist.txt | Get-RemoteProgr ...
      +                                                                  ~~~~~~~~~~~~~~~
          + CategoryInfo          : ObjectNotFound: (Get-RemoteProgram:String) [], CommandNotFoundException
          + FullyQualifiedErrorId : CommandNotFoundException
    • That is a strange error indeed, it appears that the parser does not see function as a valid keyword. Can you try to change the capital F in function to a lowercase f to see if that resolves your issue?
    • Hello again.
      I have tried that and the result remains the same :(
    • Okay can you download Get-RemoteProgram from TechNet run the following commands and share the output here:
      . .\Get-RemoteProgram.ps1
      Based on the output you generate I can take a look at what causes this behavior.
      Jaap Brasser
    • PS C:\Users\Kostas\Desktop\ps> $PSVersionTable
      Name                           Value
      ----                           -----
      CLRVersion                     2.0.50727.5485
      BuildVersion                   6.1.7601.17514
      PSVersion                      2.0
      WSManStackVersion              2.0
      PSCompatibleVersions           {1.0, 2.0}
      PSRemotingProtocolVersion      2.1
      PS C:\Users\Kostas\Desktop\ps> . .\Get-RemoteProgram.ps1
      PS C:\Users\Kostas\Desktop\ps> Get-RemoteProgram
      ProgramName                                                 ComputerName
      -----------                                                 ------------
      Microsoft Baseline Security Analyzer 2.2                    BDMIBMDC02
      Microsoft Visual C++ 2010  x64 Redistributable - 10.0.40219 BDMIBMDC02
      Microsoft Visual C++ 2012 x64 Additional Runtime - 11.0.... BDMIBMDC02
      Microsoft Visual C++ 2008 Redistributable - x64 9.0.3072... BDMIBMDC02
      Microsoft Visual C++ 2012 x64 Minimum Runtime - 11.0.51106  BDMIBMDC02
      Microsoft Visual C++ 2008 Redistributable - x64 9.0.3072... BDMIBMDC02
      VMware Tools                                                BDMIBMDC02
      Snow Inventory Client (64-bit)                              BDMIBMDC02
      McAfee Agent                                                BDMIBMDC02
      Microsoft Visual C++ 2008 Redistributable - x86 9.0.3072... BDMIBMDC02
      SRM Windows Collector                                       BDMIBMDC02
      Microsoft Visual C++ 2012 Redistributable (x64) - 11.0.5... BDMIBMDC02
      *This time the script was tested on a WS2008 R2 Standard*
  • diferent credentials
    2 Posts | Last post April 05, 2016
    • Great script and it works on my local admin pc. 
      My question is, i would love to build something in where it will take login credentials of various servers in the network and use them to extract the program`s installed on that server to an excel file.
      I`m new into powershell so i hope you can help me out a bit.
    • Hello Roermond,
      Assuming you are in a domain environment I would advice you to use an administrative account that can manage multiple servers and execute the script by using that account. If you are in a workgroup environment you could go for a similar approach by having identical accounts/passwords configured on each server and then execute the script by using that local account.
      If both those approaches are not viable for your purpose you could consider using Invoke-Command to execute commands against the servers for which you require different permissions. You could for example create a csv file with 3 columns, username, password and servername and execute commands based on that. When going for this approach I would recommend you use encrypted passwords in your excel file instead of plain text.
      To summarize, I would advise you to use one of the two options described in the first paragraph. If that is not possible then it will be slightly harder to setup.
      Jaap Brasser
  • How to sort the ProgramName Alphabetically
    19 Posts | Last post April 05, 2016
    • Minor point, but sorting alphabetically should be the default. Where would this be done?
    • Hello Leonard,
      This can be done by piping the cmdlet into Sort-Object, for example the following commands will work for this purpose:
      Get-RemoteProgram | Sort-Object -Property ProgramName
      Get-RemoteProgram | Sort ProgramName
      Does that suit your purpose?
    • o {
          If (Test-Path -Path FileSystem::c:\temp\LocalAdminsMembersAudit.csv){Remove-Item c:\temp\LocalAdminsMembersAudit.csv}  
          Write-Host "Do you want to check against a list of servers or just 1? (Enter 1 for just one , or 2 for list)" -ForegroundColor Yellow
          $Answer = Read-Host
              while( ![int]::TryParse( $Answer, [ref]$value ) ) {
                  Write-Host " "
                  Write-Host "'Please enter 1 or 2!'" -ForegroundColor Red -NoNewline
                  Write-Host " "
                  $Answer = Read-Host  
                  If ($Answer -eq 1) {
                  Write-Host "Enter the name of the server you want to check?" -ForegroundColor Yellow
                  $Computer = Read-Host
                  Get-RemoteProgram -Computername $Computer | Sort ProgramName
                  Else {
                  [System.Reflection.Assembly]::LoadWithPartialName("") | Out-Null
                  $dialog = New-Object System.Windows.Forms.OpenFileDialog
                  $dialog = New-Object System.Windows.Forms.OpenFileDialog
                  $dialog.FilterIndex = 0
                  $dialog.InitialDirectory = "C:\Temp"
                  $dialog.Multiselect = $false
                  $dialog.RestoreDirectory = $true
                  $dialog.Title = "Select a script file"
                  $dialog.ValidateNames = $true
                  $Computer = Get-content $dialog.FileName
                  Get-RemoteProgram -computername $Computer | Sort ProgramName
          Write-Host " "
          Write-Host "Do you want to check some more? (Y/N)" -ForegroundColor Yellow
          $Continue = Read-Host 
              while("y","n" -notcontains $Continue){
              Write-Host "Y or N Please!" -ForegroundColor Red
              $Continue = Read-Host 
              If($Continue -eq "Y"){}
      until ($Continue -eq "N")
    • I was trying to explain that I have somewhat of a template I use with scripts that allows me to enter a single computer or a list when evaluating a function. It is useful when I find a good function like yours. All I do, is put my code at the bottom, change the function line and after a little troubleshooting, it works.
      Yours works perfectly but again, I am trying to figure out how to sort the results alphabetically. It didn't work where I put it in my code.
      BTW, the above code should start with "Do", the "D" got cut off. Thanks for any help.
    • Also, I was trying to figure out where you got the ComputerName and ProgramName values. I was looking to add installation date but didn't know where you captured these. In the registry values you use, those values are not displayed in the "Uninstall" key. I would like to be able to grab the installation data too.
      Sorry for all the questions.
    • Indeed in the script I display the bare minimum by default, so by default only the ProgramName and the ComputerName are retrieved. It gets the computername from the input provided by the user or by looking at the hostname of the local system if no computername was provided. I have included the -Property switch to retrieve additional properties, for example you could use the following code sample:
      As for your question, I have taken a look and I have made the following changes. I will describe the changes by line number:
      Line2: Added new line of code to dot source the Get-RemoteProgram script: . C:\Scripts\Get-RemoteProgram.ps1
      Line8: Updated your while statement to match your later while statement: while(1,2 -notcontains $Answer) {
      The lines with Get-RemoteProgram, Add either | Out-String, | Format-List, | Format-Table at the end off the line to properly display the results.
      Have a look at the following examples:
      Get-RemoteProgram -Property InstallDate,DisplayVersion,Publisher,UninstallString | Sort-Object -Property ProgramName | Format-List
      If you would like a more tabular display you could also opt for the Format-Table cmdlet:
      Get-RemoteProgram -Property InstallDate,DisplayVersion,Publisher,UninstallString | Sort-Object -Property ProgramName | Format-Table -AutoSize
      And since you are already using a GUI in your example you could also go for something along these lines:
      Get-RemoteProgram -Property InstallDate,DisplayVersion,Publisher,InstallLocation,Comments,HelpLink,UninstallString | Out-Gridview
      Let me know if this helps you out and if you have any further questions let me know and I will be happy to help you out.
    • I was never a fan of the screen display you get with Format-List or using Format Table so I came up with my own way of displaying information to the screen and saving it to a CSV file. 
          process {
              foreach ($Computer in $ComputerName) {
              #Added this test for online computer
              & ping -4 -n 1 $Computer >$null
                  if($LASTEXITCODE -eq 0){
                  #Added this section to display the title line of the computer being audit seperated by a line
                  Write-Host " "
                  Write-Host "This is the software currently installed on" $Computer.ToUpper() -ForegroundColor cyan
                  Write-Host "*******************************************************************" -ForegroundColor Red
                  $RegBase = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine,$Computer)
                      foreach ($CurrentReg in $RegistryLocation) {
                          if ($RegBase) {
                              $CurrentRegKey = $RegBase.OpenSubKey($CurrentReg)
                              if ($CurrentRegKey) {
                                  $CurrentRegKey.GetSubKeyNames() | ForEach-Object {
                                      if ($Property) {
                                          foreach ($CurrentProperty in $Property) {
                                              $HashProperty.$CurrentProperty = ($RegBase.OpenSubKey("$CurrentReg$_")).GetValue($CurrentProperty)
                                      $HashProperty.ComputerName = $Computer
                                      $HashProperty.ProgramName = ($DisplayName = ($RegBase.OpenSubKey("$CurrentReg$_")).GetValue('DisplayName'))
                                      # I added this line to populate the array with the installation date I got from the registry
                                      $HashProperty.DateInstalled = ($IntallDate = ($RegBase.OpenSubKey("$CurrentReg$_")).GetValue('InstallDate'))
    • Well my last response appears to be incomplete. I am having trouble responding with complete information. There doesn't appear to be anyway to correct this. I wanted to share how I made some changes that allow me to present the information to screen in a colorful format as well as export to csv the way I need with date installed. I didn't do it the way you suggested because I like my display better. I don't know how to share that with you.
    • I believe this is the rest of the code I was trying to share. I just made comments where I added things and removed things. I still can't figure out how to sort by ProgramName when it displays to the screen.
      <# Took this section out so I could have my "colorcoded" display to the screen
                                         if ($DisplayName) {
                                         New-Object -TypeName PSCustomObject -Property $HashProperty |
                                          Select-Object -Property $SelectProperty
                                     # Added this to turn the date into the Month, Day and Year format I wanted
                                     $DateInstalled = Get-Date -Year ($HashProperty.DateInstalled).ToString().Substring(0,4) -Month ($HashProperty.DateInstalled).ToString().Substring(4,2) -Day ($HashProperty.DateInstalled).ToString().Substring(6,2) -Format "MMMM dd, yyyy"  
                                     if ($DisplayName) {
                                     #Added this section to display the results in the colors and format I wanted on the screen
                                         Write-Host $HashProperty.ProgramName -NoNewline 
                                         Write-Host " - " -NoNewline
                                         Write-Host $DateInstalled -ForegroundColor Yellow
                                     #Added the Ojbect section to give me the data I want in my CSV file 
                                         $Audit = New-Object PSOBject
                                         $Audit | Add-Member NoteProperty Server $Computer
                                         $Audit | Add-Member NoteProperty Software $HashProperty.ProgramName
                                         $Audit | Add-Member NoteProperty DateInstalled $DateInstalled
                                         $Audit | Export-Csv C:\Temp\Servers\ServerInstalledSoftware.csv -NoTypeInformation -Append
    • This is what I have been doing to try and get it to sort the ProgramName but it's not working:
      $HashProperty.ProgramName = ($DisplayName = ($RegBase.OpenSubKey("$CurrentReg$_")).GetValue('DisplayName')) | Sort-Object $DisplayName
    • Well if you do not want to use the Format- cmdlets you could do something custom like this. Here is an example using Write-Host and Export-Csv combined to generate both a csv file and colored output in the console:
                  ($Programs = Get-RemoteProgram | Sort-Object ProgramName) | Export-Csv -Path C:\Temp\Your.csv -NoTypeInformation
                  $Programs | ForEach-Object -Begin {
                      $ComputerNameColumn = ($Programs | Select-Object @{n='Count';e={$_.ComputerName.Length+1}} | Sort-Object Count)[-1].Count
                      $ProgramNameColumn  = ($Programs | Select-Object @{n='Count';e={$_.ProgramName.Length +1}} | Sort-Object Count)[-1].Count
                      Write-Host 'ProgramName'.PadRight($ProgramNameColumn) -ForegroundColor Red -NoNewline
                      Write-Host 'ComputerName'.PadRight($ComputerNameColumn) -ForegroundColor Yellow
                  } -Process {
                      Write-Host $_.ProgramName.PadRight($ProgramNameColumn) -ForegroundColor Red -NoNewline
                      Write-Host $_.ComputerName.PadRight($ComputerNameColumn) -ForegroundColor Yellow
      Let me know if that suits your purpose, as for converting dates you could use this methodology instead:
      Get-RemoteProgram -Property InstallDate,DisplayVersion,Publisher,UninstallString | Select-Object *,@{
          name       = 'ConvertedInstallDate'
          expression = {[datetime]::ParseExact($_.InstallDate,'yyyyMMdd',$null)}
    • Thanks for the suggestions. I am new to PowerShell and appreciate the opportunity to improve my code. I have much to learn.
    • Looking at your recent suggestion I notice a "(" left parenthesis on the first line in front of $Programs = Get-RemoteProgram.... I also see it a few other places. Is this a typo?
    • No problem, I like to help out when people are enthusiastic about something so no problem. Be sure to visit the Scripting Guy/ forums/boards, there are a lot of smart people sharing cool stuff and providing great learning opportunities.
      For more information on getting started with PowerShell have a look this post, it contains a number of resources to help you learn more about PowerShell:
      Jaap Brasser
    • Please disregard the question about the parenthesis. I understand where they connect.
    • Again thanks for the suggestions but I don't even know where to begin in substituting what you showed. At this point, the code that you provided in combination with my changes works exactly as I need except for sorting the Output to the screen alphabetically. Really, that's all I would like to be able to do at this point.
      My code displays the output jus the way I want it and it is something I understand. Your suggestion, although probably the best way to do it, is just a little beyond me at this point. I have to work with what I understand and it's what I have done. So thanks for the help and I will continue to review what you have suggested. But for now, except for sorting the output to the screen, what I have works and gets me the information I need whether from a single computer or a list. 
    • Hello Leonard,
      No problem, happy to help and good to hear you got the result you were looking for. Let me know if you need help with anything in the future. Have fun scripting!
      Jaap Brasser
    • Still can't figure out how to sort the display to the screen in alphabetical order. I know the software is coming from 
      $HashProperty.ProgramName = ($DisplayName = ($RegBase.OpenSubKey("$CurrentReg$_")).GetValue('DisplayName')) 
      but I don't know what object in $Hashproperty.ProgramName to sort with in order to do this, or even if this is where it could be done.
    • Hello Leonard, that is because you cannot filter on that level. $HashProperty.ProgramName is the component of an object. If you place Sort-Object there it will do nothing as the $HashProperty is only a single hashtable, nothing to sort. That is why I wrote it as:
      Get-RemoteProgram | Sort-Object ProgramName
      By doing so you will sort the collection that is output by the Get-RemoteProgram function.
  • Search for a program name
    2 Posts | Last post March 30, 2016
    • Is it possible to use this and specify to look for something?  As an example I want to see if Adobe Reader is installed.  However, some bad software companies like to include version numbers within the product name.  I would like to do something like:
      Get-RemoteProgram -Name Adobe Acrobat Reader*
    • Currently this is possible by using the Where-Object cmdlet, so for example:
      Get-RemoteProgram | Where-Object {$_.ProgramName -like 'Adobe Acrobat Reader*'}
      This also allows for additional flexibility, for example by using regular expressions, the following example only shows version 11 and 12 of Adobe reader:
      Get-RemoteProgram | Where-Object {$_.ProgramName -match 'Adobe Acrobat Reader 1(1|2)'}
  • Running against a list of computers?
    5 Posts | Last post March 25, 2016
    • Hi Jaap,
      Thanks for the script - it's great!  I wanted to know if you had a way to run it against a list of computers?  I've tried the following to no avail:
      $Servers = Get-ADComputer -Property Name -Filter {OperatingSystem -like "*server*"} | Select -property name | Sort-Object Name
      Get-RemoteProgram -ComputerName  $Servers
    • Something along these lines should work:
      $Servers = Get-ADComputer -Property Name -Filter {OperatingSystem -like '*server*'} | Select-Object -ExpandProperty Name | Sort-Object
      Get-RemoteProgram -ComputerName $Servers
      The difference is that by using -ExpandProperty you end up with an array of string. In your code sample you used -Property, then you end up with an array of custom objects with a single property, that is why it fails.
    • Hi Jaap,
      I apologize...I see you posted almost the exact answer works like a charm!
      Get-ADComputer -Filter {OperatingSystem -Like "*server*"} | Select-Object -ExpandProperty Name | Get-RemoteProgram | Select-Object ProgramName,ComputerName | Export-CSV C:\Temp\ServerPrograms.csv
    • Ah....thanks for the help Japp!
    • No problem at all, I am happy to help. Happy scripting Victor!
  • how to get list of particular software for particular vendor
    2 Posts | Last post February 19, 2016
    • Hello,
      How to get list of all computers installed Microsoft Office. 
    • Assuming you have a list of all computers in a text file you could do something along these lines:
      Get-Content -Path Computers.txt | ForEach-Object -Begin {
          . .\Get-RemoteProgram.ps1
      } -Process {
          Get-RemoteProgram -ComputerName $_
      } | Where-Object {$_.ProgramName -like 'Microsoft Office*'} | Select-Object -Property ComputerName -Unique
  • Thanks a lot, but the -Property parameter is very annoying
    2 Posts | Last post February 19, 2016
      Powershell is really great, because using
      … | Select-Object -Property *
      Users automatically gets all available properties.
      Your concept forces your users to reverse-engineer your script and then create a list of all existing uninstall-registry-values to get a list of all valid properties.
      Therefore I hope you don't intruduce a new paradigm which is very annoying. I assume you tried to optimize a performance problem which usually does not exist.
      I'm very sorry for this judgment.
      Kind regards,
    • Hello Tom,
      I am sorry to hear that you feel the script is not providing the output you expected. Just to make sure I understand you correctly, could you please explain what kind of output you expect from the script and how this is not matching.
      The reason I implemented the -Property functionality is because the keys in the registry can be different for each installed program, as manufactures can add their own registry keys. So that leaves us with two possible scenarios, either assure that every entry gets each possible property that is available in the registry, resulting in 100s of properties per object. Or we decide to define the properties per object based on what is available in the registry, but that would leave us with a collection of objects of which the properties do not match and therefore could not be placed in a csv file for example.
  • Script executes, but returns no data
    6 Posts | Last post January 05, 2016
    • Just downloaded this, and tried it out.
      I've opened a powershell console as an administrator on my own workstation and then ran it like so:
      .\Get-RemoteProgram.ps1 -computername remote-computer
      and it doesn't give any errors - just goes back to the prompt. I've dot-sourced it, and tried to run it without a computername to get my local software listing, but get the same results.
    • Could you try to first dot source the script and then access the function, try the following code:
      . .\Get-RemoteProgram.ps1
      Get-RemoteProgram -computername remote-computer
    • Was able to get a local listing when I used ". .\Get-RemoteProgram.ps1;Get-RemoteProgram", and after that in the same session was also able to get a local listing with just Get-RemoteProgram, but thereafter in the same session got an error with "Get-RemoteProgram -computername <remotecomputer>":
      Exception calling "OpenRemoteBaseKey" with "2" argument(s): "The network path was not found.
      At C:\BatchFiles\Get-RemoteProgram.ps1:73 char:13
      +             $RegBase = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microso ...
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
          + FullyQualifiedErrorId : IOException"
      I also tried it with "get-adcomputer <computername> | Get-RemoteProgram" and also just <computername> | Get-RemoteProgram" and had no luck either way.
    • Update:
      My failures above are against a Win7 machine that is domain joined. I have just now also tried against a Server 2012 R2 Terminal Server and it worked as advertised, but against a Windows 8.1 machine it fails.
    • OK - I figured some of it out. The Remote Registry service wasn't turned on for the workstations. What I can't explain is why it would be turned on for a TS server, and not for the workstations.
      Any thoughts on that?
    • It depends on how the workstations were installed, you can define which services are enabled and disabled during and after installation. If you would like to ensure which services are enabled on workstations you could use group policy if you are in a domain environment. Alternative options are:
      - Use a Configuration Management tool to configure workstations, for example: Configuration Manager 2012R2
      - Use DSC to configure workstations
      - Create a templatedisk and deploy workstations from this template
  • Get Installed program of computer in LAN
    2 Posts | Last post December 24, 2015
    • Hi every one!
      I have a mission that to check all software that installed in client computer in AD from a list ( csv, excel), for example Team Viewer and export to output file CSV . Please help me how to do ? 
    • You could do something along these lines:
      . .\Get-RemoteProgram.ps1
      Get-Content -Path C:\ComputerList.Txt | ForEach-Object {
          Get-RemoteProgram -ComputerName $_
      } | Export-Csv -Path C:\InstalledPrograms.csv -NoTypeInformation
  • how can I run this against an array containing several computernames?
    3 Posts | Last post December 07, 2015
    • for example:
      $computers = Get-ADComputer -Filter {OperatingSystem -Like "Windows 7*"} -Property * | select-object Name
      I think I need a foreach of some kind so I can execute:
      Get-RemoteProgram -Computername $computers | select-object Programname,Computername | Where-Object -Property Programname 
      any tips?
    • I may have figured it out:
      foreach ($i in $args)
      {Get-ADComputer -Filter {OperatingSystem -Like "Windows 7*"} -Property * | select-object Name}
      Get-RemoteProgram -Computername $i | select-object Programname,Computername 
    • To simplify your code you could also do something along these lines:
      Get-ADComputer -Filter {OperatingSystem -Like "Windows 7*"} | Select-Object -ExpandProperty Name | Get-RemoteProgram | Select-Object ProgramName,ComputerName
41 - 50 of 69 Items