2

Overall my goal is to get the VNC version for a list of remote computers along with the uninstall GUID so I can remotely uninstall VNC Viewer from certain computers. I have used the Get-WmiObject -Class Win32_Product but that is extremely slow.

I have the following script but in the results it includes the name of the select-object parameter.

$computers = Get-Content -Path "C:\Computers.txt"

$Results = @()

ForEach ($Computer in $Computers) {
    $Results += New-Object PSObject -Property @{
        "ComputerName" = $Computer

        "Name" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
        | Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object DisplayName

        "DisplayVersion" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
        | Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object DisplayVersion

        "ModifyPath" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
        | Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object ModifyPath

        "Vendor" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
        | Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object Publisher

    }
}

$Results | Select-Object ComputerName,Name,DisplayVersion,ModifyPath,Vendor | Sort-Object ComputerName  | Export-Csv  C:\VNC.csv -notype ;

My results look like this:

ComputerName   : ComputerName
Name                   : @{DisplayName=VNC Viewer 5.2.3}
DisplayVersion     : @{DisplayVersion=5.2.3}
ModifyPath           : @{ModifyPath=MsiExec.exe /I{18B1E36F-0DA3-4FDA-BC57-DD815B0DF3B2}}
Vendor                 : @{Publisher=RealVNC Ltd}

I would want it to look like this:

ComputerName   : ComputerName
Name                   : VNC Viewer 5.2.3
DisplayVersion     : 5.2.3
ModifyPath           : MsiExec.exe /I{18B1E36F-0DA3-4FDA-BC57-DD815B0DF3B2}
Vendor                 : RealVNC Ltd

Is this possible or am I going about this script entirely wrong? I haven't figured out a way to run this Invoke-Command for multiple parameters and still output the results in individual columns any other way.

This script works but takes forever for 100's of computers:

if (Test-Path C:\VNCInstalled.csv) {Remove-Item C:\VNCInstalled.csv}
if (Test-Path C:\Computers.txt) {Remove-Item C:\Computers.txt}
$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
$DirSearcher.Filter = '(&(objectClass=Computer)(!(cn=*esx*)) (!(cn=*slng*)) (!(cn=*dcen*)) )'
$DirSearcher.FindAll().GetEnumerator() | sort-object { $_.Properties.name } `
| ForEach-Object { $_.Properties.name }`
| Out-File -FilePath C:\Computers.txt

Get-Content -Path c:\Computers.txt `
| ForEach-Object {Get-WmiObject -Class Win32_Product -ComputerName $_} `
| Where-Object -FilterScript {$_.Name -like "VNC V*"} `
| select-object @{Name="ComputerName";Expression={$_.PSComputerName}},
                Name,
                @{Name="InstallLocation";Expression={$_.PackageCache}},
                Vendor,
                Version,
                @{Name="GUID";Expression={$_.IdentifyingNumber}} `
| Sort-Object ComputerName `
| Export-CSV -path c:\VNCInstalled.csv -notype
2
  • 4
    Try select-object -ExpandProperty DisplayVersion Commented Aug 30, 2016 at 15:11
  • Wow, that easy, awesome and thank you!! Commented Aug 30, 2016 at 15:33

1 Answer 1

4

Change all of your Select-Object commands to Select-Object -ExpandProperty PropertyName, to discard the property name / column header.

This is the answer I gave three years ago and I think it was really a poor answer. Let me do a better job now.

Why your current code is slow

Your current code enumerates all machines from AD and puts them in a file called Computers.txt. Simple, and you do it fine.

Next up, your code performs this operation:

Get-Content -Path c:\Computers.txt | 
ForEach-Object {Get-WmiObject -Class Win32_Product -ComputerName $_} `
| Where-Object -FilterScript {$_.Name -like "VNC V*"} [...]

This can be summarized as 'For each computer, request the full Win32_product table, and then after that, filter down to apps named VNC.' This is HUGELY performance impacting and for a few reasons.

  1. Even on a fast modern computer, querying Win32_Product will take 30 seconds or more, because it returns every application installed. (on a new VM for me it took more than a minute with just a handful of apps installed!)

  2. Querying Win32_Product also has this fun quirk which makes it take even longer, quoted from MSDN Documentation on the Win32_Product Class

Warning Win32_Product is not query optimized. Queries such as "select * from Win32_Product where (name like 'Sniffer%')" require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the “where” clause. This process also initiates a consistency check of packages installed, verifying and repairing the install. With an account with only user privileges, as the user account may not have access to quite a few locations, may cause delay in application launch and an event 11708 stating an installation failure. For more information, see KB Article 794524.

So to summarize, querying Win32_Product is slow, AND it also triggers a consistency chceck on every app, AND we also have this query written to retrieve every single app before filtering. These add up to a process which probably takes ~3 minutes per pc, and will operate serially (one after the other) and take forever.

How to fix it

Software info can be retrieved reliably in two places:

  • If you have SCCM/ConfigMgr installed on your devices, it adds the Win32_AddRemoveProgram WMI Class you can query, which is a super fast version of Win32_Product
  • If not, we can always retrieve info from the registry.

Here's a short snippet to get applications like VLC installed on a computer (I don't have VNC like you, so I'm making due)

Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-object DisplayName -like "VLC*" |Select-Object DisplayName, DisplayVersion, Publisher, InstallDate,UninstallString


DisplayName     : VLC media player
DisplayVersion  : 3.0.8
Publisher       : VideoLAN
InstallDate     :
UninstallString : "C:\Program Files (x86)\VideoLAN\VLC\uninstall.exe"

This operation is much faster, only 400 MS or so. Sadly we cannot get much faster using the registry as it has a very weird PowerShell provider that doesn't implement the -Filter parameter, so we do have to retrieve all programs and then filter to our desired choice.

Updating your script to use this function instead

I took the liberty of rewriting your script to use this approach, and restructured it a bit for better readability.

$results = New-object System.Collections.ArrayList
$computers = Get-Content -Path c:\Computers.txt 
foreach ($computer in $computers){
    #get VNC entries from remote computers registry
    $VNCKeys = Invoke-Command -ComputerName $computer -ScriptBlock {
        Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | 
            Where-object DisplayName -like "VNC V*" | 
                Select-Object DisplayName, DisplayVersion, Publisher, UninstallString, @{Name=‘ComputerName‘;Expression={$computer}}
        }#end of remote command

    if ($VNCKeys -ne $null){
        forEach($VNCKey in $VNCKeys){
            [void]$results.Add($VNCKey)
        } 
    }
}

$results | Sort-Object ComputerName | Export-CSV -path c:\VNCInstalled.csv -NoTypeInformation
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.