Use Powershell to get all software installed on an end-user Windows workstation
So, you’re working in an enterprise environment? Maybe you’re an Organization Unit Administrator or a Workstation Administrator. Either way, you’ve probably wished there was an easy way to remotely get the software installed on one of the workstations in your footprint. Well, fret no more! Today I’m going to share three commands you can use to get a lit of software installed on any Windows workstation. Of course, the following commands will rely on you having a remote connection to the workstation(s) in question.
You can quickly get on the target computer by running the following command:
Enter-PSSession <ComputerName>
Where is the workstation you’re interested in. You will of course need to provide credentials or have access via your Active Directory domain group permissions profile.
First Way
Get-WMIObject -Class Win32_Product
Second Way
Get-WMIObject -Class Win32Reg_AddRemovePrograms
Third Way (Comprehensive)
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object {-not [string]::IsNullOrWhiteSpace($_.DisplayName) } | Select *
Since Powershell is an object-oriented shell, you can really benefit by tweaking which data points you need using a pipe to the Select Commandlet (as shown in the last example). This make it really easy to gather information quickly, without leaving your seat, and organizing it into some kind of logical representation you can use for reporting or general oversight. Let’s switch gears and assume you have a local file with computers listed in it, and you want to get a comprehensive list of all installed software by machine. No problem! Here’s one way to tackle this:
# Your list of devices
$devices = Import-Csv "AD_Devices.csv"
# Create an empty array to hold all objects created in the script and setup analytics
$collection = @()
$deviceCount = $devices.Count
$startTime = Get-Date
$devicesUp = 0
$devicesDown = 0
$position = 1
Write-Host "Starting software enumeration of $deviceCount devices..."
foreach ($dev in $devices) {
$computerName = $dev.Name # <-- The actuall computer name - should be column name in csv
$bucketName = $dev.BucketName # <-- Bucketname in this case is the OU - should be column name too
$fqdn = "$computerName.DS.DOMAIN.YOU" # <-- Whatever your domain is...
Write-Host "Connecting to $computerName ... " -NoNewline
if (Test-Connection -Count 2 $fqdn -Quiet) {
Write-Host "Connected! " -ForegroundColor Green -NoNewline
Write-Host "Enumerating software ... " -NoNewline
$software = Get-WMIObject -ErrorAction SilentlyContinue -Class Win32Reg_AddRemovePrograms -ComputerName $computerName
if ($software) {
$softwareCount = $software.Count
foreach ($item in $software) {
$obj = New-Object PSObject
$obj | Add-Member NoteProperty ComputerName($computerName)
$obj | Add-Member NoteProperty BucketName($bucketName)
$displayName = If ($item.DisplayName -eq $null) {"Unknown"} Else {$item.DisplayName}
$obj | Add-Member NoteProperty SoftwareDisplayName($displayName)
$publisher = If ($item.Publisher -eq $null) {"Unknown"} Else {$item.Publisher}
$obj | Add-Member NoteProperty SoftwarePublisher($publisher)
$obj | Add-Member NoteProperty InstallDate($item.InstallDate)
$obj | Add-Member NoteProperty ProductID($item.ProdID)
$obj | Add-Member NoteProperty Version($item.Version)
$collection += $obj
}
Write-Host $softwareCount" programs found! " -ForegroundColor Green -NoNewline
} else {
Write-Host "No Software! " -ForegroundColor Red -NoNewline
}
$place = $deviceCount - $position
$position += 1
$devicesUp += 1
Write-Host "$place devices left" -ForegroundColor Green
} else {
$place = $deviceCount - $position
$position += 1
Write-Host "Unable to connect! $place devices left" -ForegroundColor Red
$devicesDown += 1
}
}
$endTime = Get-Date
$duration = 'Operation took: {0:mm} min {0:ss} sec' -f ($endTime-$startTime)
Write-Host $duration
Write-Host "Devices up: $devicesUp - Devices down: $devicesDown"
Write-Host 'Exporting CSV data...'
$collection | Export-Csv -NoTypeInformation Discovered_Software.csv
Write-Host 'Complete!' -ForegroundColor Green
Of course, this is only one way to do it, and it uses some pre-suppositions i.e. what your columns are named in your CSV file. As you get better at powershell, you’ll be able to define your own PSObjects to hold the exact data you want. In the end, it just makes your life a hell of a lot easier when you can run a script against a known set and then get the data you need. As an aside, Powershell is not known for being “fast” - LOL. So, if you run this against 1K computers or more, then you should expect a good three-hour run! Hope these solutions help you out!