PowerShell – Program List – 32/64 Bit – Local/Remote Machies

This Powershell script list all the installed application on both 32 and 64 bit applications, particularly useful for people managing both 32-bit and 64-bit applications.   This code also contains an exclusion array where you can exclude list of program that you don’t want to show.

  • The function allows -ComputerName parameter so you can connect to any machines
  • Application architecture detection (32-bit or 64-bit) using Win32_processor
  • Output is Powershell console and GridView

Function call:- The computer name is mandatory to retrive the software list.

Get-InstalledApplication -Computername <Computername>

Code:

Function Get-InstalledApplication
{ 
Param( 
[Parameter(Mandatory=$true)] 
[string[]]$Computername) 

#Registry Hives 

$Object =@() 

$excludeArray = ("Security Update for Windows", 
"Update for Windows", 
"Update for Microsoft .NET", 
"Security Update for Microsoft", 
"Hotfix for Windows", 
"Hotfix for Microsoft .NET Framework", 
"Hotfix for Microsoft Visual Studio 2007 Tools", 
"Hotfix") 

[long]$HIVE_HKROOT = 2147483648 
[long]$HIVE_HKCU = 2147483649 
[long]$HIVE_HKLM = 2147483650 
[long]$HIVE_HKU = 2147483651 
[long]$HIVE_HKCC = 2147483653 
[long]$HIVE_HKDD = 2147483654 

Foreach($EachServer in $Computername){ 
$Query = Get-WmiObject -ComputerName $Computername -query "Select AddressWidth, DataWidth,Architecture from Win32_Processor"  
foreach ($i in $Query) 
{ 
 If($i.AddressWidth -eq 64){             
 $OSArch='64-bit' 
 }             
Else{             
$OSArch='32-bit'             
} 
} 

Switch ($OSArch) 
{ 

 "64-bit"{ 
$RegProv = GWMI -Namespace "root\Default" -list -computername $EachServer| where{$_.Name -eq "StdRegProv"} 
$Hive = $HIVE_HKLM 
$RegKey_64BitApps_64BitOS = "Software\Microsoft\Windows\CurrentVersion\Uninstall" 
$RegKey_32BitApps_64BitOS = "Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" 
$RegKey_32BitApps_32BitOS = "Software\Microsoft\Windows\CurrentVersion\Uninstall" 

############################################################################# 

# Get SubKey names 

$SubKeys = $RegProv.EnumKey($HIVE, $RegKey_64BitApps_64BitOS) 

# Make Sure No Error when Reading Registry 

if ($SubKeys.ReturnValue -eq 0) 
{  # Loop Trhough All Returned SubKEys 
ForEach ($Name in $SubKeys.sNames) 
 { 
$SubKey = "$RegKey_64BitApps_64BitOS\$Name" 
$ValueName = "DisplayName" 
$ValuesReturned = $RegProv.GetStringValue($Hive, $SubKey, $ValueName) 
$AppName = $ValuesReturned.sValue 
$Version = ($RegProv.GetStringValue($Hive, $SubKey, "DisplayVersion")).sValue  
$Publisher = ($RegProv.GetStringValue($Hive, $SubKey, "Publisher")).sValue  
$donotwrite = $false 

if($AppName.length -gt "0"){ 

 Foreach($exclude in $excludeArray)  
                        { 
                        if($AppName.StartsWith($exclude) -eq $TRUE) 
                            { 
                            $donotwrite = $true 
                            break 
                            } 
                        } 
            if ($donotwrite -eq $false)  
                        {                         
            $Object += New-Object PSObject -Property @{ 
            Appication = $AppName; 
            Architecture  = "64-BIT"; 
            ServerName = $EachServer; 
            Version = $Version; 
            Publisher= $Publisher; 
           } 
                        } 

} 

  }} 

############################################################################# 

$SubKeys = $RegProv.EnumKey($HIVE, $RegKey_32BitApps_64BitOS) 

# Make Sure No Error when Reading Registry 

if ($SubKeys.ReturnValue -eq 0) 

{ 

  # Loop Through All Returned SubKEys 

  ForEach ($Name in $SubKeys.sNames) 

  { 

    $SubKey = "$RegKey_32BitApps_64BitOS\$Name" 

$ValueName = "DisplayName" 
$ValuesReturned = $RegProv.GetStringValue($Hive, $SubKey, $ValueName) 
$AppName = $ValuesReturned.sValue 
$Version = ($RegProv.GetStringValue($Hive, $SubKey, "DisplayVersion")).sValue  
$Publisher = ($RegProv.GetStringValue($Hive, $SubKey, "Publisher")).sValue  
 $donotwrite = $false 

if($AppName.length -gt "0"){ 
 Foreach($exclude in $excludeArray)  
                        { 
                        if($AppName.StartsWith($exclude) -eq $TRUE) 
                            { 
                            $donotwrite = $true 
                            break 
                            } 
                        } 
            if ($donotwrite -eq $false)  
                        {                         
            $Object += New-Object PSObject -Property @{ 
            Appication = $AppName; 
            Architecture  = "32-BIT"; 
            ServerName = $EachServer; 
            Version = $Version; 
            Publisher= $Publisher; 
           } 
                        } 
           } 

    } 

} 

} #End of 64 Bit 

###################################################################################### 

########################################################################################### 

"32-bit"{ 

$RegProv = GWMI -Namespace "root\Default" -list -computername $EachServer| where{$_.Name -eq "StdRegProv"} 

$Hive = $HIVE_HKLM 

$RegKey_32BitApps_32BitOS = "Software\Microsoft\Windows\CurrentVersion\Uninstall" 

############################################################################# 

# Get SubKey names 

$SubKeys = $RegProv.EnumKey($HIVE, $RegKey_32BitApps_32BitOS) 

# Make Sure No Error when Reading Registry 

if ($SubKeys.ReturnValue -eq 0) 

{  # Loop Through All Returned SubKEys 

  ForEach ($Name in $SubKeys.sNames) 

  { 
$SubKey = "$RegKey_32BitApps_32BitOS\$Name" 
$ValueName = "DisplayName" 
$ValuesReturned = $RegProv.GetStringValue($Hive, $SubKey, $ValueName) 
$AppName = $ValuesReturned.sValue 
$Version = ($RegProv.GetStringValue($Hive, $SubKey, "DisplayVersion")).sValue  
$Publisher = ($RegProv.GetStringValue($Hive, $SubKey, "Publisher")).sValue  

if($AppName.length -gt "0"){ 

$Object += New-Object PSObject -Property @{ 
            Appication = $AppName; 
            Architecture  = "32-BIT"; 
            ServerName = $EachServer; 
            Version = $Version; 
            Publisher= $Publisher; 
           } 
           } 

  }} 

}#End of 32 bit 

} # End of Switch 

} 

#$AppsReport 

$column1 = @{expression="ServerName"; width=15; label="Name"; alignment="left"} 
$column2 = @{expression="Architecture"; width=10; label="32/64 Bit"; alignment="left"} 
$column3 = @{expression="Appication"; width=80; label="Appication"; alignment="left"} 
$column4 = @{expression="Version"; width=15; label="Version"; alignment="left"} 
$column5 = @{expression="Publisher"; width=30; label="Publisher"; alignment="left"} 

"#"*80 
"Installed Software Application Report" 
"Numner of Installed Application count : $($object.count)" 
"Generated $(get-date)" 
"Generated from $(gc env:computername)" 
"#"*80 

$object |Format-Table $column1, $column2, $column3 ,$column4, $column5 
$object|Out-GridView  

}

Output:-

Image

Happy Learning

About Prashanth Jayaram

DB Technologist, Author, Blogger, Service Delivery Manager at CTS, Automation Expert, Technet WIKI Ninja, MVB and Powershell Geek My Profile: https://social.technet.microsoft.com/profile/prashanth jayaram/ http://www.sqlshack.com/author/prashanth/ http://codingsight.com/author/prashanthjayaram/ https://www.red-gate.com/simple-talk/author/prashanthjayaram/ http://www.sqlservercentral.com/blogs/powersql-by-prashanth-jayaram/ Connect Me: Twitter @prashantjayaram GMAIL powershellsql@gmail.com The articles are published in: http://www.ssas-info.com/analysis-services-articles/ http://db-pub.com/ http://www.sswug.org/sswugresearch/community/
This entry was posted in PowerShell and tagged , , , . Bookmark the permalink.

25 Responses to PowerShell – Program List – 32/64 Bit – Local/Remote Machies

  1. Darren says:

    This is exactly what I’m looking for, thank you so much! I can’t believe no one has thought to do this until now. How difficult would it be to read multiple computer names from a text file and compile into a single list?

    Like

    • Thanks for reading my space.

      The request will not much time. How do you want to have the output? Text file?

      -Prashanth

      Like

      • Darren says:

        It was simple enough to use get-childitem for a text file and call the script for each individual server. Oh one small item, I did notice that when scanning 32-bit machines, the script doesn’t check against the $excludeArray! But that was easy to fix. Also you might replacing the variable appication with application. I love this script, made my job so much easier. It belongs here: http://gallery.technet.microsoft.com/scriptcenter as well!

        Like

  2. Darren says:

    Ooops, I meant to say Get-Content, not Get-ChildItem.

    Like

  3. Jackson says:

    Fantastic script! Is there a way to output this as a CSV instead of GridView? Thanks!

    Like

  4. Dmitrii says:

    Hi Prashanth,

    Good job you have done. It can help beginners with some ready-to-use code.

    Few questions though…
    (1) What is it with code duplication (actually, triplication) and the ginormous switch statement? Isn’t it against any code guideline and good practice?

    (2) Another thing is explicit comparison against $true or $false. It is debatable in many languages, on the readability grounds; but I think such comparison is definitely unwanted in powershell, because there it certainly increases chances of bugs, because boolean can be $null and will fail comparison against both $true and $false. Next, if you happened to misspell one of the constants, it would be hard to catch that…

    I think that your
    if ($donotwrite -eq $false)
    would be better written as
    if (!$donotwrite)
    or
    if (-not $donotwrite)
    if you prefer verbosity.

    (3) would almost the same (minus architecture and excluding by arbitrary selected list) be done by the below one-liner?

    gp HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select DisplayName, DisplayVersion, Publisher, InstallDate |ogv

    With great respect,
    Dmitrii

    Like

  5. I really appreciate the time you took to describe the flaws or bad practices that needs to be overcome while writing the code. I’ll try to incorporate your advise going forward. Much appreciate. Thanks for reading and sharing your knowledge.

    Like

  6. John K. says:

    Man this script is a BLESSING!!! Thank you so much. New to powershell. Can you suggest some books / tools to get more advanced. Thank you!!!!

    Like

  7. Stan says:

    Hi Prashanth,

    can you tell me how to use the script? When trying to run it, nothing happens. No error messages, and only the command prompt clears.

    Like

    • Hi Stan,

      I think you have created the function but you are not calling the function.

      First you need create a function
      and then call the function like below

      PS:\>Get-InstalledApplication -Computername ABCD

      Let me know the steps, if you doing anything different.

      Prashanth

      Like

      • Stan says:

        Hi Prashanth,

        thank you for your answer. I did exactly as you advised and got the result – a huge table of the installed software. After that, another question came. May I somehow filter unwanted results (in my case anything which contains “Update for Microsoft Office” and “Update for Microsoft Visio”)?
        I tried to add these strings under $excludeArray in the beginning of the script, but that didn’t work: all the updates are still shown.

        Like

      • Hi Stan,

        I think the name is not right.

        Can you try to give correct application name?

        This is the logic for validation

        Foreach($exclude in $excludeArray)
        {
        if($AppName.StartsWith($exclude) -eq $TRUE)
        {
        $donotwrite = $true
        break
        }
        }
        Prashanth

        Like

      • Stan says:

        I copied and pasted the name. I don’t think it might be incorrect in this case. According to the logic for validation it should begin with these words but may not be the full name, which is variable (it shows KB# after each update). I tried to leave only word “Update” but it still shows all output nevertheless.

        Like

      • Hi Stan,

        Can you send me a screen shot to powershellsql@gmail.com?

        I will take a look at it?

        –Prashanth

        Like

      • Stan says:

        Prashanth,

        thank you so much for your time. My PowerShell knowledge is quite limited, this was the reason for such behavior. Obviously I missed very simple thing which is probably apparent for anyone more experienced. I accidentally closed my PowerShell window and after reopening it and doing Import-Module again, my changes came into force and the script now filters things which I have added in it.

        Like

      • Hi Stan,

        Did you recompile the function after adding the application to an exclude list of a function?

        I excluded many application.

        –Prashanth

        Like

  8. Stan says:

    Now I know that this is called “recompile function” 🙂

    Like

  9. Pau says:

    Hi Prashanth,

    How can you change the sorting?
    In the Out-gridview

    I see publisher – version – servername – architecture – application
    I want first collumn to be architecture – application – version – publisher and remove servername.

    Can that be done?
    Thanks

    Like

    • Hello Pau, Data formatting is not supported in Data grid view. You can drag and place it as per your requirement. Did you see there is an output to the console.

      Prashanth

      Like

      • Pau says:

        I manage to do it Prashant.

        But I’m having an issue. Our environnent only have 64OS.

        So when I’m doing the query.

        It’s showing every application in double which doesn’t reflect whats installed on the computer.

        Like

Leave a reply to Dmitrii Cancel reply