Get-WingetReport
Overview
This script audits the applications installed on a machine using a portable copy of Winget and returns the result as PowerShell objects. It runs once with administrative rights and, in that single run, prepares the machine, deploys a small audit script, runs that audit in both system and user context through scheduled tasks, collects the combined inventory, cleans up after itself, and returns an array of application objects.
Key Features:
- Portable Winget Deployment: Downloads and extracts a fully portable
winget.exewith all dependencies (VCLibs, Visual C++ redistributable) so the audit works even where Winget is not natively installed, including SYSTEM context. - Zero Window Flashing: Utilizes a custom, compiled Go executable (
SilentLauncher.exe) to guarantee that no console windows flash on the user's screen during task execution. - Structured Detection: The audit runtime uses
winget list --detailsto enumerate installed applications, which is more reliable across Winget versions and localised output than the column-basedwinget listtable. - Source Inference: When Winget does not print an
Origin Source:line for a package, the source is inferred from the header identifier pattern (12-character alphanumeric IDs map tomsstore,MSIX\andARP\prefixes map to untracked local installs, everything else maps towinget). - Install Scope Awareness: Records install scope per package. Any package whose
Installed ScopeisMachineis reported asSystemregardless of which context captured it. - Winget Validation: In user context, tests the system-installed
wingetcommand before trusting it. Falls back to portable Winget when the command is missing or returns no output. System context always uses the portable Winget. - Auto-Update Cross-Reference: Reads the
windowsAutoUpdateConfigtable (written by the companionConfigure-WingetAutoUpdate.ps1) to report whether each application has automatic updates enabled and when the update task last ran. - Signed Runtime: Deploys the audit runtime from a signed, encoded source. A readable reference is kept alongside the encoded placeholder so future maintainers can edit, re-sign, and re-encode the runtime.
- Provisions the Strapper logging module via
Install-PSGalleryModule, bypassing the PackageManagement engine and avoiding dynamic .NET DLL compilation or NuGet provider bootstrapping. - Self-Cleaning: Scheduled tasks and the deployed audit script are always removed at the end of the run. The portable Winget install and log files remain.
Requirements
- PowerShell version 5.1 or later.
- Windows 10 or later.
- Network access to ProVal's File Server to download the silent launcher (SilentLauncher.exe) and the module installer (Install-PSGalleryModule.ps1).
- Network access to www.powershellgallery.com (queried by
Install-PSGalleryModuleto resolve and download the Strapper module). - Network access to github.com for the Winget release bundle (Microsoft.DesktopAppInstaller) and 7-Zip extraction tools (ProVal-Tech/7zip).
- Network access to aka.ms for VCLibs and Visual C++ redistributable prerequisites.
- Administrative privileges (the script requires
-RunAsAdministratorto create scheduled tasks and write to$env:ProgramData).
Payload Usage
This script takes no parameters. It detects its own run context (SYSTEM or user) and adjusts behaviour automatically. Below are usage examples:
Example 1
Runs the audit and captures the returned application objects in a variable.
$packages = .\Get-WingetReport.ps1
Example 2
Runs the audit and displays the result as a table.
.\Get-WingetReport.ps1 | Format-Table DisplayName, InstalledVersion, AvailableVersion, Source, Level
Example 3
Runs the audit and shows only outdated applications.
.\Get-WingetReport.ps1 | Where-Object UptoDate -eq 0 | Format-Table DisplayName, InstalledVersion, AvailableVersion
Example 4
Runs the audit and shows only applications with automatic updates enabled.
.\Get-WingetReport.ps1 | Where-Object AutoUpdateEnabled -eq 1 | Format-Table DisplayName, PackageId, AutoUpdateRunTime
What Happens When You Run the Script
When you execute Get-WingetReport.ps1, the following steps occur in order:
- The script provisions the Strapper module via
Install-PSGalleryModuleand initialises the logging environment. - Working directories are created and secured with Everyone FullControl ACLs.
- A portable
winget.exeis downloaded, extracted, and validated (skipped if already present). - The audit runtime (
Winget-Audit.ps1) is written to disk from a signed, encoded source. SilentLauncher.exeis downloaded from ProVal's File Server.- A SYSTEM scheduled task is registered and started. The audit captures machine-scope applications and replaces the inventory table.
- If a user is logged on, a user-context scheduled task is registered and started. The audit captures user-scope applications and appends to the inventory table.
- The parent script waits for each task to finish (via a completion marker file), then reads the combined inventory.
- Both scheduled tasks are unregistered and the deployed files are deleted.
- The applications are returned as an array of
PSCustomObject.
Completion Marker Behaviour
Because SilentLauncher.exe is asynchronous, the scheduled task reports completion before the audit has actually finished. The audit writes a completion marker file (Winget-Audit-Complete.flag) in its end block — even on failure — so the parent can confirm the audit truly ended.
| Task | Marker Removed Before Start | Timeout |
|---|---|---|
| System audit | Yes | 10 minutes |
| User audit | Yes | 10 minutes |
The completion marker is written in the end block of the audit script, which always runs regardless of whether the process block succeeded or threw an error. This guarantees the parent never waits indefinitely for a task that has already finished.
Audit Runtime Behaviour
When the scheduled task fires, the runtime:
- Detects its run context (SYSTEM or User).
- In user context, tests the system-installed
wingetcommand before trusting it. Falls back to portable Winget when the command is missing or returns no output. - Queries
winget list --detailsfor all installed applications. - Parses each entry's name, ID, version, source, available upgrade, and installed scope.
- Filters out untracked local installs (bare
MSIX\orARP\identifiers with no catalog source and no pending upgrade). - Cross-references the auto-update configuration to determine per-app update status.
- Stores the result in the
windowsApplicationInventoryStrapper table (replace for SYSTEM, append for User). - Writes the completion marker file.
Generated Files and Scenario Breakdown
When the script runs, it orchestrates several files and scheduled tasks across two working directories. Below is an end-to-end breakdown of what is created and why:
-
Portable Winget (
C:\ProgramData\_Automation\App\Winget\)winget.exe: The extracted Winget binary used for all audit operations.- Supporting DLLs and dependencies extracted from the App Installer bundle.
- All intermediate artifacts (
.msixbundle,.msix,7zr.exe,7za.exe,7z.7z,.appx,VC_redist*.exe) are deleted after extraction. - This directory is not cleaned up after the run so subsequent audits skip the deployment step.
-
Audit Runtime (
C:\ProgramData\_Automation\Script\Winget-Report\)Winget-Audit.ps1: The self-contained audit script. Lists installed applications usingwinget list --details, parses each entry, cross-references the auto-update configuration, and stores the result in the Strapper table.- Deleted during cleanup.
-
Silent Launcher (
C:\ProgramData\_Automation\Script\Winget-Report\)SilentLauncher.exe: A compiled Go executable that runs scripts with the Windows APICREATE_NO_WINDOWflag. Both scheduled tasks launch the audit script through it to guarantee zero window flashing.- Deleted during cleanup.
-
Completion Marker (
C:\ProgramData\_Automation\Script\Winget-Report\)Winget-Audit-Complete.flag: Written by the audit script'sendblock (even on failure) so the parent can confirm the audit truly finished.- Deleted during cleanup.
-
SYSTEM Scheduled Task
- Task:
Winget-Report-Systemunder\WingetReport\(runs asNT AUTHORITY\SYSTEM, highest run level). - Action: Executes
SilentLauncher.exe, passingWinget-Audit.ps1as an argument. - Trigger: None (started programmatically by the parent script).
- Unregistered during cleanup.
- Task:
-
User-Context Scheduled Task (only when a user is logged on)
- Task:
Winget-Report-Userunder\WingetReport\(runs as the interactive users group, highest run level). - Action: Executes
SilentLauncher.exe, passingWinget-Audit.ps1as an argument. - Trigger: None (started programmatically by the parent script).
- Unregistered during cleanup.
- Task:
-
Inventory Table (Strapper local storage)
windowsApplicationInventory: The combined system and user inventory. The SYSTEM audit replaces the table; the user audit appends to it. Read by the parent script during collection and available to external consumers after the run.
-
Audit Runtime Logs (Strapper, written when the audit task fires)
Winget-Audit-log.txtandWinget-Audit-error.txtin the script working directory.
The audit runtime (Winget-Audit.ps1) is written from a fixed, parameterized source embedded in the script. Its on-disk content never changes between runs unless the source is edited, allowing it to be securely Authenticode signed. All varying data (Winget path, table names, marker path) is resolved at runtime from the file system and environment, ensuring the signed content remains byte-identical. The deployed .ps1 file is written as UTF-8 without a byte order mark (BOM).
Parameters
This script takes no parameters. It detects its own run context (SYSTEM or user) and adjusts behaviour automatically.
Output
Returns an array of PSCustomObject, one entry per installed application, with the following properties:
| Property | Type | Description |
|---|---|---|
DisplayName | String | Friendly name of the application. |
PackageId | String | Winget package identifier. |
InstalledVersion | String | Currently installed version, or empty when unknown. |
AvailableVersion | String | Newer version available from the source, or empty when up to date. |
Source | String | Package source (winget or msstore). |
UptoDate | Int | 1 when up to date, 0 when an update is available. |
Level | String | Context the application was captured in (System or User). Machine-scope packages captured in user context are still reported as System. |
AutoUpdateEnabled | Int | 1 when automatic updates are enabled for the application, otherwise 0. |
AutoUpdateRunTime | String | Last run time of the Winget-AutoUpdate scheduled task in yyyy-MM-dd HH:mm:ss format, or empty when not applicable. |
Files written under C:\ProgramData\_Automation\App\Winget:
winget.exeand its portable dependencies (persist across runs)
Files written under C:\ProgramData\_Automation\Script\Winget-Report (transient, removed during cleanup):
Winget-Audit.ps1(audit runtime)SilentLauncher.exe(silent launcher)Winget-Audit-Complete.flag(completion marker)Winget-Audit-log.txtandWinget-Audit-error.txt(audit runtime logs)
Local data table (managed by Strapper):
windowsApplicationInventory(combined system and user inventory)
Configuration script logs (next to this script):
.\Get-WingetReport-log.txt.\Get-WingetReport-error.txt
Changelog
2026-07-31
- Replaced the legacy
Invisible.vbsVBScript wrapper with a custom, compiled Go executable (SilentLauncher.exe), guaranteeing zero console window flashing for all scheduled tasks using the Windows APICREATE_NO_WINDOWflag. - Replaced the
Install-Module/Update-Module/Find-ModuleStrapper provisioning logic with the Install-PSGalleryModule script, retrieved at runtime from the content repository. This bypasses the PackageManagement engine entirely, eliminating dynamic .NET DLL compilation, NuGet provider bootstrapping, and the associated failure modes in constrained environments. - Added a signed, encoded deployment model for the audit runtime, with a readable here-string reference kept alongside the Base64 placeholder for future maintainers.
- Added
github.comandaka.msas explicit network requirements for the Winget bundle and redistributable prerequisites.
2026-07-20
- Updated the audit runtime to leverage
winget list --accept-source-agreements --disable-interactivity --details, improving the reliability and simplifying the parsing of package information. - Added source inference from header identifiers when the
Origin Source:detail line is absent. - Added install scope awareness: packages with
Installed Scope: Machineare reported asSystemregardless of the capturing context. - Added cross-referencing of the
windowsAutoUpdateConfigtable to report per-application auto-update status.
2026-06-29
- Initial version of the document.