Search code examples
powershellscriptingpowershell-remoting

How do I remote into multiple remote computers via PS to discover one specific app and determine the version number on each remote device? No output


FYI: I'm very new to PS and I'm using this as a learning opportunity. Again, I'm trying to find a specific application on a list of multiple remote devices and determine the version number of the application on their corresponding host system. I attempted this via a registry query (found this to be challenging) and then I used Get-WMIObject. As of now, I'm working with this as my script. It's not producing any output; instead, it returns to the command prompt with no errors or messages.

Script to find specific application and version in multiple remote devices:

    $Servers = Get-Content -Path C:\\files\Serverlist.txt

    $CIMSession = New-CIMSession -ComputerName $Servers Get-Credentials

    $Vendor = "App Name"


    foreach($Serv in $Servers) {

    If(Test-Connection -ComputerName $Serv -Count 1 -Quiet) {

    $Status = Get-Ciminstance Win32_Product -Computername $Serv | Where-object {$_.Version -contains 
    $Vendor}

    if($Status) {

    Out-file -Filepath C:\\files\AppVerResults.txt

    }

    }

    }

I also tried adjusting the following section of the script as shown below but it presented me with the error "Get-CimInstance : Access is denied." Is this error message due to group policy or so? I am able to remote into the device corresponding to the message via RDP.

    if($Status) {

     $Servers + " - "

    $Status | Out-file -Filepath C:\\files\AppVerResults.txt

    }

    }

    }

Should I go about it via invoke-command or registry query? I'm slowly picking things up so I'll continue my research but I was hoping to get some advice in the meantime.


Solution

  • I still believe searching the registry is the easier way to go unless you have the specific file path for the .exe.

    Use this function to find software on a remote, or local PC. Theres a filter option by specifying -SoftwareName (to look for).

    • Find-Software -ComputerName Remote_ComputerName -SoftwareName 'SQL'

    Also accepts pipeline input, as well as multiple computer names to query for.

    • Find-Software -ComputerName ComputerOne, ComputerTwo, ComputerThree -SoftwareName 'SQL'
    • 'ComputerOne','ComputerTwo' | Find-Software -SoftwareName 'SQL'
    • Exporting is also allowed by piping to an Export-* cmdlet.

    Heres the code:

    Function Find-Software {
    [cmdletBinding()]
        Param(
            [Parameter(Mandatory=$false,
                       ValueFromPipeLine=$true,
                       ValueFromPipeLineByPropertyName=$true)]
            [Alias('cn','name')]
            [string[]]$ComputerName = $env:COMPUTERNAME,
            
            [Parameter(Mandatory=$false)]
            [String]$SoftwareName
             )
    Begin{
    
        #Get Computer Names to check software version for
        $Server_List = Get-Content -Path "C:\files\Serverlist.txt"
        
        #Get Credentials for Script Scope once.
        $Credentials = Get-Credential
    
    }
    
    Process{
        if($PSBoundParameters.ContainsKey('SoftwareName')){
            foreach($Computer in $ComputerName){
                Try{
    
                $PSSession = New-PSSession -ComputerName $Computer -Credential $Credentials -EnableNetworkAccess -ErrorAction Stop
    
                $Software_List = Invoke-Command -ScriptBlock { 
                                    Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
                                                     "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" } -Session $PSSession
    
                $Software_List = $Software_List | Where-Object -FilterScript {$_.DisplayName -match $SoftwareName} | Sort-Object -Property DisplayName
                    foreach($Software in $Software_List){
                        if($Software){
                        [PSCustomObject]@{
                                "Computer Name" = $Computer
                                "Software Name" = $Software.DisplayName
                                "  Version  "   = $Software.DisplayVersion
                                }
                            } else {
                        [PSCustomObject]@{
                                "Computer Name" = $Computer
                                "Software Name" = "Not found"
                                "  Version  "   = $null
                            }
                        }
                    }
    
                } Catch {
                    "Unable to connect to PC: $Computer"
                    "Error: $($Error[0].Message.Split('.')[1].Trim())"
                }
            }
        } else {
            foreach($Computer in $ComputerName){
                Try{
    
                $PSSession = New-PSSession -ComputerName $Computer -Credential $Credentials -EnableNetworkAccess -ErrorAction Stop
    
                $Software_List = Invoke-Command -ScriptBlock { 
                                    Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
                                                     "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" } -Session $PSSession
                                                     
                $Software_List = $Software_List | Sort-Object -Property DisplayName
                    foreach($Software in $Software_List){
                        [PSCustomObject]@{
                                "Computer Name" = $Computer
                                "Software Name" = $Software.DisplayName
                                "  Version  "   = $Software.DisplayVersion
                                }
                            }
                        } Catch {
                            "Unable to connect to PC: $Computer"
                            "Error: $($Error[0].Message.Split('.')[1].Trim())"
                        }
                    }
                } #end ELSE statement
            } #end PROCESS block
        End {
            if(Get-PSSession){
                Get-PSSession | Remove-PSSession
            }
        } #end END block - Perform Session Clean Up
    } #end FUNCTION
    

    Simply modify it to fit your needs :)