I have done a post like this before, linked to finding "java" versions but that was a simple requirement this one is a little more complex, and you always need to improve your skills when you do the same basic task again 💀
The goal this time is to report on the version of putty and winscp installed on a list of servers, the reason for this is older version of putty and winscp have a vulnerability there the private keys can be exploited if you have local access to the server.
While this risk is small if sounded like a good requirement for a script to check this on remote servers, so the usual approach for this is to look at the registry path > HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall which is good but this was not displaying winscp whatsoever, if you tried this command:
Get-WmiObject -Class Win32_Product
That will return all the software installed which is no good, but if you used the -like variable like this it would find putty:
Get-WmiObject -Class Win32_Product | where Name -like "putty*" | select Name, Version
However, if you use the same command for winscp it returned nothing
Get-WmiObject -Class Win32_Product | where Name -like "winscp*" | select Name, Version
This is where I dropped the WmiObject query and thought there must be a better way to do this than a WMI call, so I looked on the powershell galley for this task, as there is no point reinventing the wheel with coding and I can across this galley item
https://gallery.technet.microsoft.com/Get-Programs-Installed-on-0e93f152
When I look at the code for this I noticed that it scanned the HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall as well as this key path which contains all the 64bit applications HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\ and that is what I was missing, I was only looking at the location for 32bit applicationsm, which this code nicley addresses.
Script : Get-InstalledProgram
You can get that from the link above but the syntax for that command if you wish to query a remote computer looks like this for putty and winscp:
Get-InstalledProgram.ps1 -ProgramName "putty*" -ComputerName <server> | Select-Object DisplayName, DisplayVersion
Get-InstalledProgram.ps1 -ProgramName "winscp*" -ComputerName <server> | Select-Object DisplayName, DisplayVersion
When you run that it returns this, which is good news as we now have both putty and winscp reporting back with the relevant versions, as below:
Now, I can get back to scripting (or weaponize the original script) that command now I have a command that works and this is what I came up with that works well, this will take a list of servers in a file called "servers.txt" and run those two commands from earlier against them and output them to the screen
Script - Screen Output
# Read the list of server names from the text file
$servers = Get-Content "servers.txt"
# Loop through each server and execute the commands
foreach ($server in $servers) {
Write-Host "Computer Name: $server"
# Execute the first command for WinSCP
$winscp = .\Get-InstalledProgram.ps1 -ProgramName "winscp*" -ComputerName $server | Select-Object DisplayName, DisplayVersion
# Execute the second command for Putty
$putty = .\Get-InstalledProgram.ps1 -ProgramName "putty*" -ComputerName $server | Select-Object DisplayName, DisplayVersion
# Combine data into a single table
$combinedTable = @($winscp, $putty) | Format-Table -AutoSize
# Output the table
$combinedTable
# Add a separator between outputs for each server
Write-Host "---------------------------"
}
The CSV file you get is very easy to read and filter which makes this a beautiful but deadly edition (sorry stole that from Jurassic Park) to my script library.
I'll buy that for a dollar, scripting done for this mission (sorry stole from Robocop this time)