<# .SYNOPSIS Gathers a list of installed software on a given computer. .DESCRIPTION Gathers the list of software installed for a given computer or set of computers. .PARAMETER Path Path to use to export the CSV report. If the path is not specified, results are output to the running terminal. .PARAMETER ComputerName Specifies the computers on which the command runs. The default is the local computer. .PARAMETER Credential Credential that should be used to connect to a remote machine. .NOTES Version: 1.0 Author: Tyler Hale Creation Date: 2021.09.18 #> [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory = $false)] [ValidateScript( {Test-Connection $_ -Count 2})] [alias('Cn')] [string[]] $ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory=$false, ValueFromPipeline=$true)] [ValidateNotNull()] [System.Management.Automation.PSCredential] [System.Management.Automation.Credential()] $Credential = [System.Management.Automation.PSCredential]::Empty ) ############################################### [Script Settings] ################################################ # Locations where software is registered $RegistryPaths = @( "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" "HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" ) ############################################# [Internal Processing] ############################################## <# Build Remote Parameters #> # Reference by appending @RemoteParameters to a command $RemoteParameters = @{} if ($ComputerName -ne $env:COMPUTERNAME) { Write-Verbose "Adding $ComputerName to Remote Parameters splat variable" $RemoteParameters['ComputerName'] = $ComputerName } if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) { Write-Verbose "Adding provided credentials to Remote Parameters splat variable" $RemoteParameters['Credential'] = $Credential } # Create Inventory variable $SoftwareInventories = @() # Get the current date for logging $DateCollected = (Get-Date -Format o) ################################################## [Execution] ################################################### foreach ($Computer in $ComputerName) { $SoftwareInventory = $null $SoftwareInventory = foreach ($RegistryEntry in $RegistryPaths) { Write-Verbose "Processing $RegistryEntry" foreach ($Entry in (Invoke-command {Get-ItemProperty $args[0] } -ArgumentList $RegistryEntry @RemoteParameters)) { # If DisplayName exists add it to the software inventory if (($null,'' -ne $Entry.DisplayName)) { [pscustomobject][ordered]@{ "Name" = $Entry.DisplayName "Version" = $Entry.DisplayVersion "Publisher" = $Entry.Publisher "Install Size" = $Entry.EstimatedSize "Install Location" = $Entry.InstallLocation "Uninstall String" = $Entry.UninstallString "Computer Name" = $Computer "Date Collected" = $DateCollected } } } } $SoftwareInventories += $SoftwareInventory | Sort-Object Name } if ($Path -ne "") { $SoftwareInventories | Export-Csv $Path -Force -NoTypeInformation Write-Host "Software Inventories have been exported to $Path" } else { return $SoftwareInventories }