Skip to main content

Getting a List of Installed Applications on Local and Remote Computers

Introduction

A few months ago, I was asked to have a look at a PowerShell script which was supposed to be able to list installed applications on the local and remote Windows computers on the network.

The script was from the Microsoft Gallery site.

Here is the original script, with explanations of what it's supposed to do.

https://gallery.technet.microsoft.com/scriptcenter/Get-a-List-of-Installed-c47393ed/view/Discussions

Unfortunately if you run the script, it will only list the applications installed on the local PC but outputs the same results for all the computers that you are trying to inventory.

I found that the program was very well structured so perhaps the author did this on purpose. Anyhow, I modified the Function FindInstalledApplicationInfo($ComputerName)
and used .NET's remote registry functions in place of the original PowerShell registry functions which looks at the local registry only. In this way, the .NET's remote registry functions can look at the local registry or remote Windows computers registry.

Feel free to use the whole script or if you have come to this page trying to resolve the original script's issues, just look at the FindInstalledApplicationInfo function.

Full Listing of the Get List of Installed Applications script

#--------------------------------------------------------------------------------- 
#The sample scripts are not supported under any Microsoft standard support 
#program or service. The sample scripts are provided AS IS without warranty  
#of any kind. Microsoft further disclaims all implied warranties including,  
#without limitation, any implied warranties of merchantability or of fitness for 
#a particular purpose. The entire risk arising out of the use or performance of  
#the sample scripts and documentation remains with you. In no event shall 
#Microsoft, its authors, or anyone else involved in the creation, production, or 
#delivery of the scripts be liable for any damages whatsoever (including, 
#without limitation, damages for loss of business profits, business interruption, 
#loss of business information, or other pecuniary loss) arising out of the use 
#of or inability to use the sample scripts or documentation, even if Microsoft 
#has been advised of the possibility of such damages 
#--------------------------------------------------------------------------------- 

#requires -version 3

# SoftwareAudit-Lib version 1.0 Date: 13/06/2017
#
# The system that this script runs on needs to have PowerShell 3.0 or above.
# You will also require admin rights to the PCs that are being scanned.
# 
#
# This script needs to be imported before it can be used.
# The syntax to import this script module in a PowerShell environment is:
#
# import-module "DRIVE:\Full Path\..\..\SoftwareAudit-Lib.psm1"
#
# If you are going to be running another script to make use of this script module, it is best to import this script as part of the calling script.
# This ensures the below function is available to the calling program.
#
# NOTE: If you have to make changes to any functions below, remember to exit out of a PowerShell session
# and re-import this script for the changes to take effect


Function Get-OSCInstalledApplication
{
<#
  .SYNOPSIS
        Get-OSCInstalledApplication is an advanced function which can be used to get installed application on local or remote computer.
    .DESCRIPTION
        Get-OSCInstalledApplication is an advanced function which can be used to get installed application on local or remote computer.
    .PARAMETER  ComputerName
  Gets the installed application on the specified computers. 
    .PARAMETER  ComputerFilePath
  Specifies the path to the CSV file. This file should contain one or more computers. 
    .EXAMPLE
        C:\PS> Get-OSCInstalledApplication -ComputerName "Server201201","Server201202"
  
  This command will list installed application on 'Server201201' and 'Server201202'.
    .EXAMPLE
        C:\PS> Get-OSCInstalledApplication -ComputerFilePath C:\Script\ComputerList.csv
  
  This command specifies the path to an item that contains several computers. Then 'Get-OSCInstalledApplication' cmdlet will list installed application from thoese computers.
    .EXAMPLE
        C:\PS> Get-OSCInstalledApplication -ComputerName "Server201201" | Export-Csv -Path C:\installedApps.csv
  
  This command will list installed application on 'Server201201' and saves the strings in a CSV file.
#>
    [CmdletBinding(DefaultParameterSetName='SinglePoint')]
    Param
    (
        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="SinglePoint")]
        [Alias('CName')][String[]]$ComputerName,
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="MultiplePoint")]
        [Alias('CNPath')][String]$ComputerFilePath
    )
    
    If($ComputerName)
    {
        Foreach($CN in $ComputerName)
        {
            #Test computer connectivity
            $PingResult = Test-Connection -ComputerName $CN -Count 1 -Quiet
            If($PingResult) 
            {
# If PC is on the network, start remoteregistry service on PC, then start scanning for installed apps
Set-Service –Name remoteregistry –Computer $CN -StartupType Automatic Get-Service remoteregistry -ComputerName $CN | start-service Start-Sleep -s 5 write-host "Trying to find applications on " $CN FindInstalledApplicationInfo -ComputerName $CN } Else {
# If PC is not on the network, return the PC name with one application Display Name as "Computer Offline"
       $Objs = @()
       Write-Warning "Failed to connect to computer '$CN'."
       $Obj = [PSCustomObject]@{Computer=$CN;
                                 DisplayName = "Computer Offline";
                                 DisplayVersion = "";
                                 Publisher = "";
       ApplicationType = "" }
       $Objs += $Obj
       $Objs | Where-Object { $_.DisplayName } 
            }
        }
    }

    If($ComputerFilePath)
    {
        $ComputerName = (Import-Csv -Path $ComputerFilePath).ComputerName

        Foreach($CN in $ComputerName)
        {
            FindInstalledApplicationInfo -ComputerName $CN
        }
    }
}

# This next function checks the Software Uninstall registry of the PC and lists the values, which represents
# the installed applications

Function FindInstalledApplicationInfo($ComputerName)
{

$Objs = @()

$key = "Software\Microsoft\Windows\CurrentVersion\Uninstall"
$key_32bit = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"

$type = [Microsoft.Win32.RegistryHive]::LocalMachine

$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $ComputerName)
$subRegKey=[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $ComputerName)

$regKey_32bit = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $ComputerName)
$subRegKey_32bit = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $ComputerName)


#Check if it is a 64 bit PC by checking the existence of the Software Wow64Node. It is 64 bit if the
#Wow64Node exists.

$is64Bit=$regKey_32bit.OpenSubkey($key_32bit)

if ($is64Bit -eq $null) { $applicationBitType="32 Bit"
} else {
  $applicationBitType="64 Bit"
}

# Getting the list of installed applications from the SOFTWARE Uninstall Registry Key
# They are 64 bit if the Wow64Node exists, otherwise the applications are 32 bit.

$regKey = $regKey.OpenSubKey($key)
$sub=$regKey.GetSubKeyNames()


Foreach($sub1 in $sub){
  $subKey=$key + "\" + $sub1.toString()

  $InstalledApp=$subRegKey.OpenSubKey($subKey)

    
     
    $Obj = [PSCustomObject]@{Computer=$ComputerName;
                                 DisplayName = $InstalledApp.GetValue("DisplayName");
                                 DisplayVersion = $InstalledApp.GetValue("DisplayVersion");
                                 Publisher = $InstalledApp.GetValue("Publisher");
            ApplicationType = $applicationBitType }
     
 
 $Objs += $Obj
  
}


# Getting the list of installed 32 bit Applications for a 64 bit PC

if ($is64Bit -ne $null) {
$regKey_32bit = $regKey_32bit.OpenSubkey($key_32bit)
$sub_32bit=$regKey_32bit.GetSubKeyNames()


 Foreach($sub1_32bit in $sub_32bit){
  $subKey_32bit=$key_32bit + "\" + $sub1_32bit.toString()
  
  $InstalledApps_32bit=$subRegKey_32bit.OpenSubKey($subKey_32bit)
  
 
    
 $Obj = [PSCustomObject]@{Computer=$ComputerName;
                                 DisplayName = $InstalledApps_32bit.GetValue("DisplayName");
                                 DisplayVersion = $InstalledApps_32bit.GetValue("DisplayVersion");
                                 Publisher = $InstalledApps_32bit.GetValue("Publisher");
            ApplicationType = "32 Bit" }
      
  
  
  $Objs += $Obj
 }
}

$Objs | Where-Object { $_.DisplayName } 


}

Comments

Popular posts from this blog

How To Migrate Mailboxes from Exchange 2010 to Exchange 2016 using PowerShell

The Scenario

Your organisation have decided to migrate from Exchange 2010 to Exchange 2016. The Exchange 2016 server have been installed into your current Exchange Organization. The Mailbox role have been installed on the Exchange 2016 server and you are ready to start moving mailboxes from the Exchange 2010 server to the Exchange 2016 server.

Migrating a Mailbox from Exchange 2010 to Exchange 2016

Using New-MoveRequest

Migrating a single mailbox involves invoking the cmdlet New-MoveRequest from the Exchange Management Shell on the Exchange 2016 server. Make sure that your user account that you have logged into the server with have the Organization Management role.

The common parameters that I use for the New-MoveRequest cmdlet is :

New-MoveRequest -Identity 'useralias@somedomain.com' -TargetDatabase "DB02" -BadItemLimit 10

The -Identity parameter identifies the mailbox to be migrated. I usually use the e-mail address of the mailbox for the identity since it's uniqu…

How to Schedule an Exchange PowerShell Script in Task Scheduler

Exchange Management Shell
Since Exchange 2007, Microsoft has provided the Exchange Management Shell so administrators can manage all aspects of the Exchange server from the command line.



The Exchange Management Shell has Exchange specific PowerShell cmdlets. These Exchange cmdlets are not normally available in an ordinary PowerShell command environment.



An example of what can be done in the Exchange Management Shell is to run a PowerShell script to list all the mailboxes on the Exchange server to a file. You can output columns based on display name, size of the mailbox, last logon, and other available mailbox attributes.

You can also schedule a batch migration of mailboxes from one database to another such as the migration of mailboxes from Exchange 2010 to Exchange 2013.

Scheduling the PowerShell Script

Once you have written a PowerShell script and utilised the Exchange cmdlets, you can run it with no problems inside the Exchange Management Shell. If you were to try to run it under a …