This project streamlines packaging and updating Win32 apps in Microsoft Intune using winget metadata and recipe-driven automation.
- Windows Forms GUI (recommended):
Start-AutoPackagerGUI.ps1 - Command line:
AutoPackagerv2.ps1with flags
This README provides a GUI quick start, CLI quick start, and a reference background process. The GUI Help tab loads this content.
- Prerequisites
- GUI Quick Start
- Config-driven defaults (GUI)
- Command Line Quick Start
- Background Process (Reference)
- Appendix: Recipe fields (overview)
- Notes and alignment with the current code
- Windows PowerShell 5.1
- PowerShell modules:
intunewin32app,powershell-yaml,Microsoft.winget.client- Example (run in an elevated PowerShell prompt and accept agreements):
Install-Module intunewin32app Install-Module powershell-yaml Install-Module Microsoft.winget.client
- Example (run in an elevated PowerShell prompt and accept agreements):
- Internet connectivity
- For FullRun (Intune upload/updates):
- Azure AD App Registration with
DeviceManagementApps.ReadWrite.All, and credentials (Client Secret or Certificate thumbprint) via:AZInfo.csvnext toAutoPackager.ps1, orAutoPackager.config.json(AzureAuth), or- CLI parameters to
AutoPackager.ps1
- Create a GitHub PAT Token (will be needed or you will hit api limits with GitHub when running AutoPackager)
- Setup Automation
- Automation Account
- Create a local windows account or domain service account that can be used as the account for the scheduled task. System may work too, but if you do not choose a domain account you will not be able to archive to a network folder (setup in the autopackager.config.json file.
- Scheduled task (#10-Scheduled-Task)
- Create a new Scheduled task on a workstation or server that will run Autopackager and read the recipes nightly.
- Automation Account
- Azure AD App Registration with
- Right-click
Start-AutoPackagerGUI.ps1and choose “Run with PowerShell” - Or run from console:
powershell.exe -ExecutionPolicy Bypass -File .\Start-AutoPackagerGUI.ps1
- Winget Search: Enter search criteria for the software you are looking for
- Winget ID: Enter the package ID (e.g.,
zoom.zoom) - Locale: Defaults to
en-US - Architecture:
x64/x86/arm64(sets appropriate download) - Installer Type:
msi/exe(sets appropriate download) - Buttons:
- Search Winget
- Searches winget for the criteria entered and displays the output for selection
- If only one package matches, it will auto-select and fill in the Winget ID field
- Validate Winget ID
- Executes:
Find-WingetPackage -id <WingetID> -MatchOption Equals
- Displays raw output and also parses plain text to extract
- Executes:
- Show Installer YAML
- Displays raw output of the installer YAML so you can determine which Architecture and Installer Types are available
- Download Installer
- Downloads the parsed
InstallerUrl(if available) into:Testing\Publisher\Name\Version - Behavior:
- Safe filename/path sanitation
- TLS 1.2 where possible; sets a common User-Agent
- Tries
Invoke-WebRequestfirst; falls back toStart-BitsTransfer - Shows the destination and byte size on success
- Downloads the parsed
- Search Winget
- Winget ID is synchronized with Winget and Recipe tabs (editing in one updates the others)
- Create App(s)
- Icon: Pick an image (
png/jpg/jpeg) to use as the app icon (when supported by auth method) - Create Primary App
- Create Required Update App
- Both use
CreateWin32AppFromTemplate.ps1to create minimal placeholder Win32 apps, using DisplayName derived from winget (Name + optional Version) and Publisher when available. The Required Update app appends a display name suffix fromAutoPackager.config.json:SecondaryRequiredApp.DisplayNameSuffix(preferred) orSecondary.DisplayNameSuffix(fallback)
- The new AppId is detected from command output and written into:
- Recipe tab (
Primary IntuneAppIdorSecondaryAppId) - Intune App(s) tab (read-only fields)
- Recipe tab (
- Both use
- Icon: Pick an image (
- AppId(s)
- Read-only Primary AppId and Required Update AppId fields reflect results from Create/Find actions
- Reset AppId(s) clears those fields and the related fields on the Recipe tab
- Select Existing App(s)
- Search Name auto-populates with the vendor segment (e.g.,
jabra.direct->jabra) when empty; user edits are preserved - Find Primary App / Find Required Update App:
- Searches existing Win32 apps by “display name contains”
- On multiple matches, a pick-list is presented
- Selected AppId is written to both this tab and the Recipe tab
- Search Name auto-populates with the vendor segment (e.g.,
- Output window shows echoed commands and results
- Create / Select
- Winget ID (synced across tabs)
- Create New Recipe: runs
New-RecipeFromWinget.ps1to generate a starter recipe file under.\Recipes - Browse Recipe…, Open in Notepad, Open recipe folder
- Select Existing App(s)
- Search Name and Find buttons behave like the Intune App(s) tab. When invoked here, the GUI switches to the Intune App(s) tab to show output/selection, then automatically returns
- Quick Edit (IDs and Args)
- Primary AppId (
IntuneAppId), Required Update AppId (SecondaryAppId)- Note: The GUI does not enforce GUID format; it writes values as provided
- Installer Scope: Writes
InstallerPreferences.Scopein the recipe ("",machine, oruser). Leave blank to honor defaults/CLI fallback - Architecture: Writes to recipe (used for application download selection)
- Installer Type: Writes to recipe (used for application download selection)
- InstallArgs / UninstallArgs
- ForceUninstall (boolean)
- ForceTaskClose (multiline; one process name per line;
.exeextension is optional) - Notification Popup
- Enabled
- Timer (minutes)
- Allow deferral
- Deferral hours (see CLI notes for how deferral horizon is computed at runtime)
- Required Update Deployment Rings
- Pilot Group + Deadline (days)
- UAT Group + Deadline (days)
- GA Group + Deadline (days)
- Load Default Groups: reads
RequiredUpdateDefaultGroupsfromAutoPackager.config.json
- Save Recipe Update(s)
- Apply writes the current Quick Edit values back into the JSON (
ConvertTo-Json -Depth 15)
- Apply writes the current Quick Edit values back into the JSON (
- Primary AppId (
- Mode
- Package Only (Testing Output)
- Full Run (Update Intune)
- Optional: No Azure Authentication (adds
-NoAuthto backend)
- Target
- Select Recipe File… (single
.jsonfile)
- Select Recipe File… (single
- Run AutoPackager
- Safely builds and executes
AutoPackager.ps1with the selected options - Output window shows stdout/stderr and a tail of
AutoPackager.logwhen present
- Safely builds and executes
- Notes
- GUI Run tab targets one recipe file at a time. To process all recipes or run DryRun, use the CLI (see below) or set defaults in
AutoPackager.config.json
- GUI Run tab targets one recipe file at a time. To process all recipes or run DryRun, use the CLI (see below) or set defaults in
- Primary AppId Reset / Required Update AppId Reset
- Uses
IntuneApplicationResetAll.ps1with-AppIdwhen available - If an AppId is provided, the GUI attempts to run in-process and capture output; otherwise an external PowerShell window may open for prompts (especially for the secondary button when no AppId is provided)
- Uses
- Refresh Log: Tails
AutoPackager.log(up to 500 lines) - Open Working Folder
- Open Latest Summary CSV (
Working\Summary_*.csv)
- Open
AutoPackager.config.json - Open
readme.txt(this file) - Open
SystemConfigReadMe.txt
- Run Prerequisite Check
- Loads the content of
readme.txtinto the window
Wherever you setup the Scheduled task share the Recipe Folder in the Script location. This will be used for the Autopackager.config.json file for the RecipeNetworkFolder field.
- Create a user with rights to all local folders and network paths listed in the AutoPackager.config.json file.
- Create a Scheduled Task
- General Tab
- Name: AutoPackager - Nightly Run
- Select User Account
- Select Run whether user is logged on or not
- Select Run with highest privledges
- Triggers Tab
- Select run schedule (I run it daily at 12:01 AM every day)
- Actions Tab
- Action: Start a program
- Program/Script: c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe
- Add arguments (optional): -NoProfile -executionpolicy bypass -file ".\autopackagerv2.ps1" -fullrun -allrecipes
- Start in (optional): (example: D:\AutoPackager)
- General Tab
On GUI startup, when AutoPackager.config.json is present the GUI reads and applies:
- Run Mode default (
PackagingDefaults.RunMode:PackageOnlyorFullRun) - Winget defaults (
PackagingDefaults.WingetSource,PackagingDefaults.DefaultScope) - Preferred architecture (
PackagingDefaults.PreferArchitecture:x64/x86/arm64) for Winget parsing - Notification defaults (
Notification.Defaults:Enabled,TimerMinutes,DeferralEnabled,DeferralHoursAllowed) - Default Required Update ring group names (
RequiredUpdateDefaultGroups) via “Load Default Groups”
Note: Verification flags (SkipVerify, StrictVerify) are honored by the backend if configured, but they are not exposed as GUI toggles.
From the AutoPackager root folder:
-
Package only, single recipe (default mode without
-FullRun):powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -PathRecipes ".\Recipes\your.app.json"
-
Full run, all recipes in default
Recipesfolder:powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -FullRun -AllRecipes
-
Full run, one specific recipe:
powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -FullRun -PathRecipes ".\Recipes\your.app.json"
-
Package-only without Intune authentication (skip connection):
powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -PackageOnly -PathRecipes ".\Recipes\your.app.json" -NoAuth
-
Dry Run (no download/wrap/upload; compares Intune vs winget):
powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -DryRun
AZInfo.csv(optional) next toAutoPackager.ps1:Non-empty values override CLI params;TenantId,ClientId,ClientSecret,CertificateThumbprintClientSecrettakes precedence overCertificateThumbprint.- Or configure
AutoPackager.config.json(AzureAuth), or pass CLI parameters directly.
-PreferArchitecture x64|x86|arm64-DefaultScope machine|user
Note: RecipeInstallerPreferences.Scope(if set) is honored first;-DefaultScopeapplies when recipe scope is blank.-NoAuth(skip Intune connection for packaging/troubleshooting)-SkipVerify/-StrictVerify(control post-upload verification)-UpdateDetection/-NoUpdateDetection-NoUpdateCmds(skip install/uninstall command updates)
AutoPackager.login the root (rotated/archived toWorking\AutoPackager_yyyyMMdd_HHmmss.log)Working\Publisher\Name\Version\Downloadfor downloaded installers (+ generated install/uninstall scripts are copied here)Working\Publisher\Name\Version\Scriptsfor generated scriptsWorking\Publisher\Name\Version\Output\Package\*.intunewinWorking\Summary_*.csvfor run summaries
- Use the gui to locate winget packages by searching for part of the name.
- Review the output and select the appropriate option
- Select Show Installer YAML
- Ensure you can target a machine-scope installer
- Test run the installer to gather and document the install silent switches for the recipe file
- Test run the uninstaller to gather and document the uninstall silent switches for the recipe file
Uninstall command lines can generally be found in the registry under:HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
- Option A (portal): Create two Win32 apps manually and record their AppId GUIDs
- Option B (recommended): Use the GUI Intune App(s) tab “Create Primary App” and “Create Required Update App” buttons, optionally providing an icon. The GUI will write the new AppIds into the Recipe Quick Edit fields.
- From GUI: Recipe tab -> “Create New Recipe” from a Winget ID
- Or from console: run
New-RecipeFromWinget.ps1(prompted or-wingetidparameter) - The file is created in
.\Recipesand can be edited in the GUI Quick Edit or a text editor
Required fields to validate/fill for production:
IntuneAppId: Primary app GUID (if you intend FullRun)SecondaryAppId: Required Update app GUID (if you intend FullRun with secondary)InstallerPreferences.Scope: If you must force machine/user to resolve the correct installerInstallArgs/UninstallArgs: Silent switches, restart behavior, etc.ForceTaskClose: One process name per line that must be closed before install/upgrade/uninstall
Optional fields:
ForceUninstall: Uninstall previous version before installingNotificationPopup:EnabledNotificationTimerInMinutes(default 2)DeferralEnabled(default true)DeferralHoursAllowed(default 24)
- Rings (for the Required Update app):
Ring1/2/3:Group(display name) andDeadlineDelayDays(int)
- GUI: Run tab -> Package Only -> select one recipe -> Run AutoPackager
- CLI:
powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -PackageOnly -PathRecipes ".\Recipes\your.app.json"
- Test run and validate successful Install/Uninstall/Detection/Requirement Scripts using PowerShell on a test machine
- Install/Uninstall scripts are located in:
<AutoPackager V3>\Working\Publisher\Name\Version\Download - Detection/Requirement scripts are located in:
<AutoPackager V3>\Working\Publisher\Name\Version\Scripts
- Install/Uninstall scripts are located in:
- GUI: Run tab -> Full Run -> select the recipe file -> Run AutoPackager
- CLI:
powershell.exe -ExecutionPolicy Bypass -File .\AutoPackager.ps1 -FullRun -PathRecipes ".\Recipes\your.app.json"
- Verify the Intune App Metadata and Detection Scripts are properly set on primary application
- Verify the Intune App Metadata, Detection Script, and Requirement Script are properly set on secondary required application
- Advertise Primary App to a test group and validate Intune Application Deployment
- Advertise Secondary Required App to a test group and validate Intune Application Deployment
- Use the GUI Reset tab or run:
.\IntuneApplicationResetAll.ps1 -AppId <GUID>
- Update the recipe (
InstallArgs,ForceTaskClose,NotificationPopup, Rings, etc.) - Full Run with appropriate assignments/groups and deadlines for the Required Update app
- Confirm deployments and behavior through Intune for both Primary and Required Update Apps
- If you need to re-stage for more testing, reset the apps again:
.\IntuneApplicationResetAll.ps1 -AppId <GUID>
WingetId: Required (e.g.,"zoom.zoom")IntuneAppId: Primary Win32 app GUIDSecondaryAppId: Required Update Win32 app GUID (orSecondary.IntuneAppId/AppId/Id)InstallerPreferences:Scope:"machine"|"user"|""(blank for default behavior)Architecture:"x64"|"x86"|"arm64"(optional)
InstallArgs/UninstallArgs: Silent switches for vendor installer/uninstallerForceUninstall: booleanForceTaskClose: array or multiline string of process names to closeNotificationPopup:Enabled: booleanNotificationTimerInMinutes: intDeferralEnabled: booleanDeferralHoursAllowed: int
Rings:Ring1/2/3:{ Group: "display name of Entra group", DeadlineDelayDays: int }
- Winget parsing in the GUI uses plain-text parsing; scope in the Winget tab is a selection preference and not added to the winget command there. The backend (CLI) uses JSON where available and falls back to text, adding/removing
--scopeas needed for compatibility. - GUI Run tab supports
PackageOnlyandFullRunfor a single selected recipe; use the CLI if you want-AllRecipesor-DryRunfrom the console. - Reset actions use
IntuneApplicationResetAll.ps1with-AppId. The GUI attempts inline execution when GUIDs are provided and falls back to an external PowerShell window if needed. - Quick Edit does not enforce GUID format; it writes values exactly as provided.
- The GUI reads defaults from
AutoPackager.config.jsonfor run mode, winget preferences, and notification behavior.


