AppList.psm1
function Get-InstalledApps { <# .Synopsis Installed apps for PowerShell .Description This script outputs the list of programs in Installed apps on Windows 10 and 11 (formerly Apps & features) #> #Desktop/Win32 apps function Get-AppsFromReg { param($Regkey = $(throw = "Missing required parameter Regkey")) Get-ItemProperty $Regkey | Where-Object {($_.SystemComponent -ne 1) -and ($null -ne $_.DisplayName) -and ($null -eq $_.ReleaseType)} | Select-Object @{label="Name";expression={$_.DisplayName}},Publisher,@{label="Type";expression={"Desktop"}} } $regkey64 = "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" $regkey32 = "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" $regkeyuser = "REGISTRY::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" $apps64bit = Get-AppsFromReg -regkey $regkey64 $apps32bit = Get-AppsFromReg -regkey $regkey32 $appsuser = Get-AppsFromReg -regkey $regkeyuser $desktopapps = @() $desktopapps += $apps64bit $desktopapps += $apps32bit $desktopapps += $appsuser #Modern/Metro/UWP apps <# The following function converts indirect strings. For example, it converts: ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_OutlookDesktop_DisplayName to Mail and Calendar C# code to expose SHLoadIndirectString(), derived from: Title: Expand-IndirectString.ps1 Author: Jason Fossen, Enclave Consulting LLC (www.sans.org/sec505) Date: 20 September 2016 URL: https://github.com/SamuelArnold/StarKill3r/blob/master/Star%20Killer/Star%20Killer/bin/Debug/Scripts/SANS-SEC505-master/scripts/Day1-PowerShell/Expand-IndirectString.ps1 License: "Public domain, no rights reserved, no warranties or guarantees." #> function Expand-IndirectString{ Param([String] $IndirectString = "") # Source code in C# to P/Invoke SHLoadIndirectString from shlwapi.dll: $CSharpSHLoadIndirectString = @' using System; using System.Text; using System.Runtime.InteropServices; using Microsoft.Win32; namespace SHLWAPIDLL { public class IndirectStrings { [DllImport("shlwapi.dll", CharSet=CharSet.Unicode)] private static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, string ppvReserved); public static string GetIndirectString(string indirectString) { try { int returnValue; StringBuilder lptStr = new StringBuilder(1024); returnValue = SHLoadIndirectString(indirectString, lptStr, 1024, null); if (returnValue == 0) { return lptStr.ToString(); } else { return null; //return "SHLoadIndirectString Failure: " + returnValue; } } catch //(Exception ex) { return null; //return "Exception Message: " + ex.Message; } } } } '@ # Create the type [SHLWAPIDLL.IndirectStrings]: # Check if type is already created to avoid TYPE_ALREADY_EXISTS exception if ("SHLWAPIDLL.IndirectStrings" -as [type]) {} else {Add-Type -TypeDefinition $CSharpSHLoadIndirectString -Language CSharp} # Call method to expand the indirect string: [SHLWAPIDLL.IndirectStrings]::GetIndirectString($IndirectString) } #load list of provisioned apps that don't appear in Installed apps #Windows 10 $blacklist10 = @("Microsoft.StorePurchaseApp","Microsoft.VP9VideoExtensions", "Microsoft.Wallet" "Microsoft.XboxGameOverlay","Microsoft.XboxIdentityProvider","Microsoft.XboxSpeechToTextOverlay", "Microsoft.MicrosoftEdge.Stable") #Windows 11 $blacklist11 = @("Microsoft.DesktopAppInstaller","Microsoft.HEIFImageExtension","Microsoft.StorePurchaseApp", "Microsoft.VP9VideoExtensions","Microsoft.WebMediaExtensions","Microsoft.WebpImageExtension", "Microsoft.XboxGameOverlay","Microsoft.XboxIdentityProvider","Microsoft.XboxSpeechToTextOverlay", "MicrosoftWindows.Client.WebExperience","Microsoft.MicrosoftEdge.Stable","Microsoft.OneDriveSync", "Microsoft.HEVCVideoExtension","Microsoft.RawImageExtension") #Check OS build $osbuild = (Get-ItemProperty "REGISTRY::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion").CurrentBuildNumber #22000 is Windows 11, if less than 22000 then Windows 10 if ($osbuild -lt 22000) {$blacklist = $blacklist10} else {$blacklist = $blacklist11} #Handle Windows 10 with Pwsh (PowerShell Core) if (($osbuild -lt 22000) -and ($PSVersionTable.PSEdition -eq "Core")) {Import-Module -Name Appx -UseWindowsPowerShell -WarningAction Ignore} #Get all packages except those with System signature and no install loction $allpackages = Get-AppxPackage -PackageTypeFilter Main | Where-Object {($_.InstallLocation -ne $null) -and ($_.SignatureKind -ne "System")} | Select-Object -ExpandProperty Name -Unique #Diff blacklisted apps $whitelist = Compare-Object $allpackages $blacklist | Select-Object -ExpandProperty InputObject $packages = $whitelist | ForEach-Object {Get-AppxPackage $_} #Declare array $modernapps = @() #Loop through each package foreach ($pkg in $packages) { $manifest = $pkg | Get-AppxPackageManifest $apps = $manifest.package.Applications.Application # Show the package display name if more than one app in package # Otherwise, if there's only one app in the package, show the app display name if ($apps.Count -gt 1) { $DisplayName = $manifest.Package.Properties.DisplayName } else { $DisplayName = $manifest.Package.Applications.Application.VisualElements.DisplayName } #If the DisplayName contains ms-resource: it's an indirect string that we need to transpose to #@{PackageFullName?ms-resource:Resources/AppDisplayName} syntax if ($DisplayName -match "ms-resource:") { #If there's not Resources/ after ms-resource: and it's not ms-resources:// #then add it so it's ms-resource:Resources/ if (($DisplayName -notmatch "Resources/") -and ($DisplayName -notmatch "ms-resource://")) { $DisplayName = $DisplayName.Insert(12,"Resources/") } #Convert to name as it displays in Installed apps $DisplayName = Expand-IndirectString "@{$($pkg.PackageFullName)?$DisplayName}" } # Grab Publisher from manifest $PublisherDisplayName = $manifest.Package.Properties.PublisherDisplayName #wrap in custom object for output purposes $objApp = [PSCustomObject]@{ Name = $DisplayName Publisher = $PublisherDisplayName Type = "Modern" } #append to array $modernapps += $objApp } # Combine desktop and modern apps $allapps = @() $allapps += $desktopapps # Remove duplicates $allapps += $modernapps | Select-Object Name,Publisher,Type -Unique $allapps | Sort-Object Name } function Get-ProgramsAndFeatures { <# .Synopsis Programs and Features for PowerShell .Description This script outputs the list of programs in Programs and Features on Windows 10 and 11 #> function Get-AppsFromReg { param($Regkey = $(throw = "Missing required parameter Regkey")) Get-ItemProperty $Regkey | Where-Object {(($null -ne $_.DisplayName) -and ($_.SystemComponent -ne 1) ` -and ($null -ne $_.UninstallString) -and ($null -eq $_.ReleaseType)) ` -or (($null -ne $_.DisplayName) -and ($_.SystemComponent -ne 1) ` -and ($_.NoRemove -eq 1) -and ($null -eq $_.UninstallString) ` -and ($null -eq $_.ReleaseType) -and ($_.WindowsInstaller -eq 1))} | Select-Object DisplayName,Publisher,InstallDate,EstimatedSize,DisplayVersion } $regkey64 = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" $regkey32 = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" $regkeyuser = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" $apps64bit = Get-AppsFromReg -regkey $regkey64 $apps32bit = Get-AppsFromReg -regkey $regkey32 $appsuser = Get-AppsFromReg -regkey $regkeyuser $allapps = @() $allapps += $apps64bit $allapps += $apps32bit $allapps += $appsuser $allapps | Sort-Object DisplayName } Export-ModuleMember -Function Get-InstalledApps, Get-ProgramsAndFeatures |