-
-
Save TylerJWhit/f596c307cf87540842281a8a20149f9a to your computer and use it in GitHub Desktop.
# Version: 0.5 | |
# Date: 2019-01-30 | |
# File Name: Get-InstalledApps | |
# Author: TylerJWhit | |
# Notes: | |
# The following commands may be of help: | |
# | |
# Run against every computer in domain. | |
# Get-ADComputer -Filter * | Select-Object -ExpandProperty Name | Get-InstalledApps | |
# | |
# Run against CSV (replace path with location of file and ensure A1 says 'computername': | |
# Get-InstalledApps -computers (Import-Csv -Path C:\Computers.csv | Select-Object -ExpandProperty computername) | |
# | |
# Run against computers listed in command: | |
# Get-InstalledApps -computers HOSTNAMEA,HOSTNAMEB | |
function Get-InstalledApps { | |
Param ( | |
[CmdletBinding()] | |
[Parameter(ValueFromPipeline=$true)] | |
[Alias('name')] # Helps with 'Select-Object -ExpandProperty Name' | |
[string[]]$computers = $env:COMPUTERNAME | |
) | |
process { | |
foreach($computer in $computers){ | |
write-verbose -verbose -message "`nStarting scan on $computer" | |
Invoke-Command -Computername $computer -ErrorAction SilentlyContinue -ErrorVariable InvokeError -Scriptblock { | |
$installPaths = @('HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall','HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall') | |
Get-ChildItem -Path $installPaths | Get-ItemProperty | Sort-Object -Property DisplayName | Select-Object -Property DisplayName, DisplayVersion, Publisher, UninstallString, Version | |
} | |
if ($invokeerror){ | |
Write-Warning "Could not communicate with $computer" | |
} # if ($invokeerror) | |
} # foreach($computer in $computers) | |
} # process | |
} # function Get-InstalledApps |
Need to be able to parse this output : Get-ADComputer -Filter * | Select Name | Get-InstalledApps
Get-InstalledApps -Computers (Import-Csv -Path C:/path/to/file.csv)
is also not parsing the info correctly.
Question 1:
Get-ADComputer -Filter * | Select Name
That gets the Name object but what you want is the actual value of that object. Change it to Get-ADComputer -Filter * | Select-Object -ExpandProperty Name
Your pipeline is expecting a raw string format, not a NoteProperty.
Last, consider adding -Filter {(enabled -eq $True)}
to Get-ADComputer to filter out disabled machines.
In order for Get-InstalledApps to be at the end of the pipeline, it has to be set to accept pipeline input. This is done with cmdletbinding and [Parameter(ValueFromPipeline=$true)]
parameters. Read up on value by pipeline here
It looks like you've already done that, so once you fix the part that is passing a valid computername down the pipeline, that part should work.
Question 2:
We'd need to know the headers in the csv file in order to know the exact import code. Assuming header1 is "hostname"
Get-InstalledApps -Computers (Import-Csv -Path C:\path\to\file.csv | Select-Object hostname)
The Select Name statement works with the Alias, but it's only trying the last entry piped to it. The Import-Csv keeps parsing the name like this: @{computername=hostname}
Get-InstalledApps -computers (Import-Csv -Path C:\computername.csv | Select-Object -ExpandProperty computername)
fixed the issue. I was missing -ExpandProperty
My last issue is iteration of the Piped values instead of simply running against the last value.
Last piece of the puzzle: missing the process bracket.
A few things:
Invoke-Command -Cn $computername
I would suggest don't use aliases (
-Cn
) in scripts (Save that for ad-hoc shell interaction). It tends to lead to confusion, especially if others will be reviewing your work. Along those lines, alse define-ScriptBlock
instead of just {}Invoke-Command -ComputerName $computername -ScriptBlock { }
These can be condensed into a single line, no line break needed.
Write-Verbose -Message "Starting scan on $computername"
Convert $Computers to a parameter, and give it a default value (or make it mandatory). This will default to the current computer.
You can still import your csv if you want.
-Computers (Import-Csv -Path C:\path\to\file.csv)
Consider using
-Count 1
forTest-Connection
to limit number of pings from 4 to 1. This should improve pipeline processing time considerably.Here is the dramatic difference between the two: (
TotalSeconds
)Without
-Count 1
With
-Count 1