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
(64)
104,771 times
Add to favorites
Operating System
8/5/2019
E-mail Twitter del.icio.us Digg Facebook
Sign in to ask a question


  • The script doesn't output anything
    2 Posts | Last post April 24, 2016
    • As we heavily lock down workplaces, and amongst others the remote registry service
      was not started. I don't get a single error, the output is just blank, I run it on my local desktop with Administrative rights. I changed the execution policy.
      I see it queries [Microsoft.Win32.RegistryKey], I was wondering is there some .NET version required to operate this ? 
      The script is very usefull ..... I hope to get it up and running.
      
    • Hello Steft,
      
      If the .Net classes are missing it should definitely prompt for errors, could you check the $Error variable to see if there aren't any errors in there. The MSDN entry for this class shows that it has at least been present since .Net 1.1, so that should not be a problem.
      
      If the remote registry is not running that is an issue, as the script relies on the availability of that. Can you verify that the remote registry service is available on the system you are querying?
  • Question on placement in Powershell Script
    4 Posts | Last post April 15, 2016
    • For the below:
      Get-Content -Path C:\test\servers.Txt | ForEach-Object -Begin {
          . .\Get-RemoteProgram.ps1 
      } -Process {
          Get-RemoteProgram -ComputerName $_ -Property InstallDate,Version
      } | Where-Object {$_.ProgramName -like 'Microsoft Silverlight*'}
      
      Where would I place this in the script to get it functioning properly?  We are looking to get the same information here and this is most helpful so far.  In addition, am wanting to utilize a list of servers, which the servers.txt in the above would accomplish, correct?
      
      Appreciate any assistance that can be provided, still learning PowerShell scripting.
    • You would not put this in the script, this would be one of the ways to execute the script. If you would like you could store this in another script file in order to more easily call the script or create a custom alias or a function, but I would not recommend modifying the script in order to get this output.
      
      Here is a less verbose, shorter version by using aliases:
      cat C:\test\servers.Txt|%{. .\Get-RemoteProgram.ps1} {Get-RemoteProgram -C $_ -P InstallDate,Version}|?{$_.ProgramName -like 'Microsoft Silverlight*'}
      
      So my question now is, why would you want to store this inside of the script? What are you trying to accomplish then I can think along with you and give you some suggestions based on that.
      
    • What I was wanting to include in the script is to have it pull the install date and version information by default.  Using a file for the server list is the best way for me to run the script.  
    • One of methods you could use is to set the default parameter values using $PSDefaultParameterValues, to read more about using that you can type the following:
      Get-Help about_Parameters_Default_Values
      Or visit the following website:
      https://technet.microsoft.com/en-us/library/hh847819.aspx
      
      If you want to edit the script, I suggest you edit line 56 and 58 in the parameter block to set the default there:
      $ComputerName = (cat c:\test\servers.txt),
      [string[]]$Property = @('InstallDate','Version')
  • Adding Display Version
    4 Posts | Last post April 14, 2016
    • Hi Japp,
      
      How can we take InstalledDate and Version of the product from the below query. I  have tried to add InstalledDate and Version but no result.
      
      Thanks in Advance.
      
      Get-Content -Path C:\test\servers.Txt | ForEach-Object -Begin {
          . .\Get-RemoteProgram.ps1 
      } -Process {
          Get-RemoteProgram -ComputerName $_
      } | Where-Object {$_.ProgramName -like 'Microsoft Silverlight*'} | select -Property ComputerName,ProgramName -Unique
    • Hello Syed Kaliff,
      
      What you could do is the following:
      
      Get-Content -Path C:\test\servers.Txt | ForEach-Object -Begin {
          . .\Get-RemoteProgram.ps1 
      } -Process {
          Get-RemoteProgram -ComputerName $_ -Property InstallDate,Version
      } | Where-Object {$_.ProgramName -like 'Microsoft Silverlight*'}
      
      Do note that not all properties might be displayed in the console depending on your PowerShell. If you want to ensure all properties are visible in the console you could use the Format-* cmdlets, if you would like to view the output outside of the console you could export it to csv/xml/json.
      
      Let me know if this helps.
    • Thanks Japp,
      
      Its working fine :)
    • I am glad to hear that Syed, thanks for confirming that the solution works as intended. Have fun scripting today!
      
      
      Regards,
      
      Jaap Brasser
  • Possible to exclude certain entries on the list?
    13 Posts | Last post April 12, 2016
    • Is it possible to exclude an array of entries from the list of programs. This pulls all the programs in the uninstall registry location, such as all the windows updates and some unnecessary programs.  
      
      
    • Absolutely, you could pipe the results of Get-RemoteProgram into the Where-Object cmdlet to filter the results. For example to filter any program that contains KB000000 notation you could use the following code:
      
      Get-RemoteProgram | Where-Object {$_.ProgramName -notmatch 'KB\d+'}
      
      Alternatively you could include the SystemComponent or the IsMinorUpgrade properties and filter on that:
      
      Get-RemoteProgram -Property SystemComponent | Where-Object {-not $_.SystemComponent}
      
      Get-RemoteProgram -Property IsMinorUpgrade | Where-Object {-not $_.IsMinorUpgrade}
    • Thank you for the quick reply Jaap! This is so useful!
    • No problem, happy to help let me know if you have any additional question.
      
      Regards,
      
      Jaap Brasser
    • Hi Japp, 
      
      I do have another question. So I am trying to exclude a bigger list of programs. Right now I am just piping the where-object for each program I want exclude.
      i.e.
      
      Get-RemoteProgram -computername $computerName -property SystemComponent | Where-Object {$_.ProgramName -notmatch 'KB\d+'} | where-object {-not $_.SystemComponent} | where-object {$_.programName -notmatch 'Microsoft Visual*'} | where-object {$_.programName -notmatch 'Driver*'} | where-object {$_.programName -notmatch 'Microsoft Application Virtualization*'} |
      where-object {$_.programName -notmatch 'Adobe Reader XI'} | where-object {$_.programName -notmatch 'Adobe Shockwave Player 11.5'} | where-object {$_.programName -notmatch 'Crystal Reports Viewer 2008'} |where-object {$_.programName -notmatch 'OMM_*'} | sort-object -property programName | Format-Table -Property programName, InstallDate -autosize
    • Sure so to start what you could do is combine this into a single Where-Object cmdlet, you can use the -and and -or parameters, for example you could shorten your command to this:
      
      Get-RemoteProgram -computername $computerName -property SystemComponent | Where-Object {($_.ProgramName -notmatch 'KB\d+') -and (-not $_.SystemComponent) -and ($_.programName -notlike 'Microsoft Visual*') -and ($_.programName -notlike 'Driver*') -and ($_.programName -notlike 'Microsoft Application Virtualization*') -and ($_.programName -notlike 'Adobe Reader XI') -and ($_.programName -notlike 'Adobe Shockwave Player 11.5') -and ($_.programName -notlike 'Crystal Reports Viewer 2008') -and ($_.programName -notlike 'OMM_*')} | sort-object -property programName | Format-Table -Property programName, InstallDate -autosize
      
      Now this is still a long command, most of this comes from the fact that there is no comparison operator that matches on regular expressions. I noticed that you used the *-symbol in your example, so I assumed you meant to use the -like operator rather than the -match operator. In the next example I have created an array of statements to compare against, this makes it easier to later add additional programs, for example something along these lines:
      
      $Regexes = 'Microsoft Visual*','Driver*','Microsoft Application Virtualization*','Adobe Reader XI','Adobe Shockwave Player 11.5','Crystal Reports Viewer 2008','OMM_*'
      Get-RemoteProgram -ComputerName $computerName -Property SystemComponent | Where-Object {($_.ProgramName -notmatch 'KB\d+') -and (-not $_.SystemComponent) -and $($ProgramName=$_.ProgramName;if (($Regexes | ForEach-Object {$ProgramName -notlike $_}) -contains $false) {$false} else {$true})}
    • The array is exactly what i was looking for. Thanks again Jaap!
    • No problem, happy to help!
      
      If you are interested we could even simplify this further by using regular expressions.
      
      
      Regards,
      
      Jaap Brasser
    • I would definitely be interested in that. Anything to simplify a code is good value :).
    • Alright, here is an example entirely based on regex in combination with SystemComponent:
      
      $RegEx = 'KB\d+|^Microsoft Visual.*|^Driver.*|^Microsoft Application Virtualization.*|^Adobe Reader XI|Adobe Shockwave Player 11.5|Crystal Reports Viewer 2008|OMM_.*'
      Get-RemoteProgram -computername $computerName -property SystemComponent | Where-Object {($_.ProgramName -notmatch $RegEx) -and (-not $_.SystemComponent)}
      
      I am not sure how familiar you are with regular expressions, so let me know if you need any explanation of the regular expression as I have defined it above. What I did is make a regular expressions that matches your like expressions as closely as possible. Let me know if this works for you.
    • I understand off the regex in $RegEx except for the first one "KB\d+". Can you explain this one.
    • Disregard my last comment. I understand all of it now. Thanks Jaap!
      
      I do have another issue. I'm trying to export my list to a csv, but I'm getting guid's as the program name and my other columns don't even show up.
      
      This is my code:
      
      $Regexes = 'Microsoft Visual*','Driver*','Microsoft Application Virtualization*','Adobe Reader XI (11.0.09)','Adobe Shockwave Player 11.5','Crystal Reports Viewer 2008','OMM_*', 'Google Chrome', 'API Calculator 3.3.0.0', 'EnCompass', 'Junos Pulse 5.0', 'Microsoft Office 2010 Primary Interop Assemblies', 'Microsoft Office Professional Plus 2010', 'McAfee*', 'Adobe Flash Player 20*', 'Adobe Shockwave Player*', 'HP Hotkey Support', 'Juniper*', 'TRAC 2', 'Training and Certification*', 'Microsoft Lync 2013','OM Manuals', 'SCCM Log File Folder', 'Blueprint Tracker Installer', 'Diskeeper 12 Professional', 'Microsoft OneDrive*', 'System Center Configuration Manager Console', 'Carbon Black Sensor', 'Globalscape Mail Express Outlook Addin'
      Get-RemoteProgram -ComputerName $computer -Property SystemComponent | 
                                  Where-Object {
                                      ($_.ProgramName -notmatch 'KB\d+') -and (-not $_.SystemComponent) -and $($ProgramName=$_.ProgramName;
                                          if (($Regexes | ForEach-Object {$ProgramName -notlike $_}) -contains $false) 
                                              {
                                                  $false
                                              } 
                                          else 
                                              {
                                                  $true
                                              }
                                          )
                                  } | sort-object -property programName | Format-Table -Property programName, InstallDate -autosize | Export-Csv -Path C:\temp\test.csv -NoTypeInformation
    • Hello Richard,
      
      I will answer your first question as a reference for anyone reading back on this later, the regular expression:
      KB\d+
      
      The letter KB stand for the letters KB \d+ stands for a number and + means one or more. This means that it will match for KB followed by 1 or more numbers.
      
      As for your second question the problem is with Format-Table, or actually any of the Format-* parameters in PowerShell. If you format output it will look pretty in the console but you will no longer be able to process it as structured data. This is because the actual objects are converted to a special formatted type that displays well in the PowerShell console. So you would get the output your expect if you remove the following bit from your code:
      
      | Format-Table -Property programName, InstallDate -autosize
      
      Let me know if that answers your questions.
  • 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:
      
      $PSVersiontable
      . .\Get-RemoteProgram.ps1
      Get-RemoteProgram
      
      Based on the output you generate I can take a look at what causes this behavior.
      
      
      Regards,
      
      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}
      SerializationVersion           1.1.0.1
      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.
      
      
      Regards,
      
      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("System.windows.forms") | 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
                  $dialog.ShowDialog()
                  $dialog.FileName
      
                  $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/PowerShell.com/PowerShell.org/Reddit-PowerShell 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:
      http://www.jaapbrasser.com/how-to-learn-powershell/
      
      
      Regards,
      
      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!
      
      Regards,
      
      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 below...it 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. 
      
      Thanks
      
    • 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
41 - 50 of 73 Items