Automated Software Inventory Report with PowerShell (Win 10/11)
Difficulty: Intermediate | Time Required: 20-30 minutesIntroduction
- Keeping an up-to-date view of installed software on Windows 10 and Windows 11 machines helps with license compliance, security patching, and asset management. A local, repeatable inventory report lets you spot outliers, track version gaps, and share a clean list with your IT team. In this tutorial, you’ll learn a practical PowerShell approach to generate a comprehensive software inventory, including both traditional desktop apps and Windows Store apps.
- A Windows 10 or Windows 11 machine (version information noted below) with PowerShell 5.1 (default on Windows 10/11) or PowerShell 7.x installed.
- Administrative privileges are recommended for full access to uninstall registry keys.
- Basic familiarity with PowerShell syntax and saving scripts to a file.
- Optional: A destination folder you want to export reports to (CSV/HTML).
- A CSV inventory file (compact, sortable in Excel or any spreadsheet)
- An HTML report (readable in a browser with formatting)
- Optional: A combined view that includes Windows Store (Appx) apps via Get-AppxPackage
1) Open PowerShell with the right privileges
- Right-click the Start button, choose Windows PowerShell (Admin) or PowerShell 7.x (Admin) if installed.
- If you’re testing, you can start without admin, but some uninstall registry keys may be more complete with elevated rights.
- Create a folder for your reports, for example:
- C:\Inventory\Reports
- Create it from PowerShell (optional):
- New-Item -Path "C:\Inventory\Reports" -ItemType Directory -Force
- Save the following as InventorySoftware.ps1 or paste it into a new PowerShell ISE/VS Code session. This script enumerates software from standard uninstall registry keys (per-machine and per-user) and also pulls Windows Store apps (Appx) to provide a comprehensive view. It exports both CSV and HTML reports with a timestamp.
Code:
# InventorySoftware.ps1
# Generates a software inventory report for Windows 10/11 (local machine) # 1) Collect desktop/Store uninstall entries
$registryPaths = @( "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*") $softwareFromRegistry = foreach ($path in $registryPaths) { if (Test-Path $path) { Get-ItemProperty -Path $path -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -and $_.DisplayName -ne "" -and ($_.SystemComponent -ne 1) } | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate }
} # 2) Collect Windows Store (Appx) apps for All Users
try { $storeApps = Get-AppxPackage -AllUsers | ForEach-Object { [pscustomobject]@{ DisplayName = $_.Name DisplayVersion = $_.Version Publisher = $_.Publisher InstallDate = "" # Appx doesn't always expose a clean InstallDate here } }
} catch { $storeApps = @
} # 3) Normalize and combine results
$combined = @ foreach ($row in $softwareFromRegistry) { $combined += [pscustomobject]@{ DisplayName = $row.DisplayName DisplayVersion = $row.DisplayVersion Publisher = $row.Publisher InstallDate = if ([string]::IsNullOrWhiteSpace($row.InstallDate) { "" } else { $row.InstallDate } }
} # Append Appx results, avoiding duplicates by DisplayName
foreach ($app in $storeApps) { $exists = $combined | Where-Object { $_.DisplayName -eq $app.DisplayName } if (-not $exists) { $combined += [pscustomobject]@{ DisplayName = $app.DisplayName DisplayVersion = $app.DisplayVersion Publisher = $app.Publisher InstallDate = $app.InstallDate } }
} # 4) Optional: Clean up InstallDate into a friendlier format if possible
$formatted = $combined | ForEach-Object { $inst = $_.InstallDate if ($inst -and $inst -match '^\d{8}$') { try { $_ | Add-Member -NotePropertyName InstallDateFriendly -NotePropertyValue:([datetime]::ParseExact($inst, 'yyyyMMdd', $null).ToShortDateString -Force } catch { $_ | Add-Member -NotePropertyName InstallDateFriendly -NotePropertyValue $inst -Force } } elseif ($inst) { $_ | Add-Member -NotePropertyName InstallDateFriendly -NotePropertyValue $inst -Force } else { $_ | Add-Member -NotePropertyName InstallDateFriendly -NotePropertyValue "" -Force } $_
} # 5) Export reports
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$docPath = "$env:USERPROFILE\Documents\SoftwareInventory_$timestamp" # Create directory if needed
New-Item -Path $docPath -ItemType Directory -Force | Out-Null $csvPath = "$docPath\SoftwareInventory.csv"
$htmlPath = "$docPath\SoftwareInventory.html" $formatted | Sort-Object Publisher, DisplayName | Export-Csv -Path $csvPath -NoTypeInformation
$formatted | Sort-Object Publisher, DisplayName | Select-Object DisplayName, DisplayVersion, Publisher, InstallDateFriendly | ConvertTo-Html -Title "Software Inventory Report" -PreContent "<h2>Software Inventory Report</h2><p>Generated: $(Get-Date)</p>" | Out-File -FilePath $htmlPath -Encoding UTF8 Write-Host "Inventory reports generated:"
Write-Host "CSV: $csvPath"
Write-Host "HTML: $htmlPath"
- Save and run:
- If you saved as InventorySoftware.ps1, run:
- powershell -NoProfile -ExecutionPolicy Bypass -File "C:\Path\To\InventorySoftware.ps1"
- If you run into policy restrictions, use the bypass flag shown above or temporarily adjust the execution policy with caution:
- Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
- Open the HTML report in a browser for a nicely formatted view.
- Open the CSV file in Excel or another spreadsheet program to filter, sort, and analyze (e.g., by Publisher, by Version, or by InstallDate).
- If you want this to run automatically (weekly or monthly), create a scheduled task:
- Open Task Scheduler -> Create Task
- General: Name it “Software Inventory”
- Triggers: Weekly or Monthly, set your preferred cadence
- Actions: Start a program
- Program/script: powershell.exe
- Add arguments: -NoProfile -ExecutionPolicy Bypass -File "C:\Path\To\InventorySoftware.ps1"
- Conditions/Settings: Configure as needed (e.g., run only if user is logged on, run with highest privileges)
- Include Store apps with Get-AppxPackage
- Note that Appx data may differ in structure and is not always perfectly aligned with uninstall registry data. The script includes Appx by-name, version, and publisher for a broader view.
- Filtering system components
- The uninstall registry entries sometimes include SystemComponent=1 for non-user-facing components. The script filters these by default, but you can adjust the filter if you need to include or exclude additional entries.
- 64-bit vs 32-bit considerations
- The script queries both HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall and HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall to cover 64-bit and 32-bit apps.
- InstallDate handling
- Registry InstallDate values can be formatted differently (yyyyMMdd, etc.. The script attempts to present a friendlier date when possible, but some entries may have missing dates.
- Centralized reporting for multiple machines
- For larger environments, consider running this as a startup script via Group Policy or a central management tool, then collate CSVs from multiple machines into a single workbook. You can extend the script to write outputs to a network share if needed.
- Security and privacy
- Inventory data can reveal software details that may be sensitive. Ensure appropriate permissions and protect exported reports, especially on shared systems.
- You now have a practical, repeatable method to produce a comprehensive software inventory for Windows 10/11 using PowerShell. The workflow covers traditional desktop installations and Windows Store apps, with convenient CSV and HTML outputs suitable for audits, software compliance checks, or asset management reviews.
- By extending the script (for example, integrating remote data collection via PowerShell Remoting or adding version comparison against a license catalog), you can scale this approach to whole departments or organizations.
- A centralized, repeatable inventory helps with license compliance, security hygiene, and asset tracking on Windows 10/11.
- The recommended approach uses registry-based uninstall data (and optionally Appx) to generate a robust local software report.
- Export formats (CSV and HTML) support easy sharing, filtering, and presentation to stakeholders.
- Scheduling reports keeps you up to date with minimal effort, and you can extend the script for broader enterprise usage.
This tutorial was generated to help WindowsForum.com users get the most out of their Windows experience.