0

I want to be able to look for an installed program in powershell and output to a file the results. So far, I have something that will list the install programs, and select the string that has the name of the program, but I am not sure how to specify a text file for it to use for the list of systems, and a way to make it output cleanly.

Get-WmiObject -Class Win32_Product -cn $computernamehere | Select-Object -Property Name | Sort-Object Name | Select-String Vmware | Out-File C:\Users\ajstepanik\Desktop\installed_programs.txt

I would like it to output in a fashion like:

COMPUTER1 - VMware Horizon View Client
COMPUTER2 - VMware Horizon View Client
COMPUTER3 - VMware Horizon View Client

Currently it outputs:

@{Name=VMware Horizon View Client}
@{Name=VMware Horizon View Client}
@{Name=VMware Horizon View Client}
Aaron
  • 3,135
  • 20
  • 51
  • 78
  • 1
    Part of this is you should be using `Select-Object -ExpandProperty Name` which would just return the strings instead of an object property. – Matt Dec 10 '14 at 16:36
  • 1
    Instead of using Get-WmiObject, give a try with Get-ItemProperty much faster : Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName | ?{$_ -match "Vmware"} | Out-File C:\Users\ajstepanik\Desktop\installed_programs.txt – expirat001 Dec 10 '14 at 17:08
  • 1
    @expirat001 If I recall there was another question from Aaron where he did origianaly use that as a search method. WMI was chosen as an alternate so that he would not have to worry about the remote registry service. – Matt Dec 10 '14 at 17:18
  • 1
    Also, `Get-ItemProperty` can't target remote systems. – Bacon Bits Dec 10 '14 at 17:39

2 Answers2

1

In your case I recant my previous statement about -ExpandProperty. I am still right in that it will return just a string array instead of the object property. However I think that you will have more options if you leave it as an object and just add the property "Computer" which you are looking for. That was we can just have it as a nice CSV! I am going to assume there is some loop structure here that you have not shown.

$list = Get-Content C:\Users\ajstepanik\Desktop\computers.txt
$list | ForEach-Object{
    $computer = $_
    Get-WmiObject -Class Win32_Product -ComputerName $computer | 
            Select-Object -Property Name | 
            Sort-Object Name | 
            Where-Object{$_.Name -match "Citrix"} | 
            Add-Member -MemberType NoteProperty -Name "Computer" -Value $computer -passthru
} | Export-Csv -NoTypeINformation -Path C:\temp\path.csv

Changed the select-string to a WherenMatch since i kept the object. Used Add-Member to add a property for Computer. Now we can use Export-CSV

Forgot about foreach($x in $y) doesnt work with output the way the other foreach does.

Matt
  • 45,022
  • 8
  • 78
  • 119
  • $list = C:\Users\ajstepanik\Desktop\computers.txt is that right or am I doing it wrong? – Aaron Dec 10 '14 at 17:38
  • I am getting an error with the last pipe: At C:\Users\ajstepanik\Desktop\test.ps1:49 char:3 + } | Export-Csv -NoTypeINformation -Path C:\Users\ajstepanik\Desktop\installed_pr ... + ~ An empty pipe element is not allowed. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordEx ception + FullyQualifiedErrorId : EmptyPipeElement – Aaron Dec 10 '14 at 18:10
  • @Aaron Do you get output without the export line present? and changed the search string from Citrix to VMware? – Matt Dec 10 '14 at 18:18
  • I do not. there is something about the $list that it doesnt like. I just do $list = C:\Users\ajstepanik\Desktop\computers.txt correct? – Aaron Dec 10 '14 at 18:20
  • I get an error on | Export-Csv -NoTypeINformation -Path C:\temp\path.csv --- it says "An empty pipe element is not allowed" – Aaron Dec 10 '14 at 18:27
  • With your $list now updated you still get the same error? Let me test some more. I will fix this. you did change the match correct? @Aaron – Matt Dec 10 '14 at 18:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/66600/discussion-between-matt-and-aaron). – Matt Dec 10 '14 at 18:32
0

Let C:\ComputerList.txt be a list of computers with one computer name on each line like:

COMPUTER1
COMPUTER2
COMPUTER3
COMPUTER4

So, here's how I would do it:

$ComputerListFile = 'C:\ComputerList.txt';
$OutputFile = 'C:\VMWareSoftwareReport.csv';

#Variable for the report with header
$Report = @();
$Report += '"ComputerName","SoftwareName","SoftwareVersion"';

#Get the list of computers
$ComputerList = Get-Content $ComputerListFile;

$ComputerList | ForEach-Object {
    $ComputerName = $_;
    #Ping the target to see if it's there
    If ((Get-WmiObject Win32_PingStatus -Filter "Address='$ComputerName' AND Timeout=1000").StatusCode -eq 0) {
        #Get the list of software
        $vmWareSoftware = Get-WmiObject -Query "SELECT Name, Version FROM Win32_Product WHERE Name LIKE '%vmWare%'" -ComputerName $ComputerName | Sort-Object -Property Name;
        $vmWareSoftware | ForEach-Object {
            #Format the results, escape any double quotes, and add them to the report
            $SoftwareName = $_.Name.Replace('"','""');
            $SoftwareVersion = $_.Version.Replace('"','""');
            $Report += '"{0}","{1}","{2}"' -f $ComputerName, $SoftwareName, $SoftwareVersion;
        }
    }
}

#Write the report file, overwriting if needed
Set-Content -Path $OutputFile -Value $Report -Force;

You might want to use Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* as @expirat001 mentions, but Get-ItemProperty can't target remote computers. It also may not be a complete listing. For that matter, Win32_Product may not be complete, either. There's no comprehensive way to find all installed software in Windows.

Note also that Out-File by default will overwrite, not append. You have to specify the -Append switch, or you'd just get the one computer in the file.

Bacon Bits
  • 30,782
  • 5
  • 59
  • 66