Skip to content

Intune + Winget: Win32 Deployments & Templates

Estimated Time: 20–40 min  Skill: Intermediate  Goal: Deploy apps via Winget + Intune using reusable scripts & Win32 packaging

This guide provides a practical, copy-paste ready template for deploying Win32 apps with Winget via Microsoft Intune.
Use the scripts below as templates — search for the package Id via winget search, replace PACKAGE_ID, then package with the Microsoft Win32 Content Prep Tool.


OverviewMethodsScripts (template)Packaging & Intune settingsDetection & Error HandlingTrusted Sources & Why WingetExample: Find PACKAGE_IDWinget-AutoUpdateScript SigningTL;DRReady-to-copy commands


Overview

Winget (Windows Package Manager) lets you install and manage apps via a package ID from a trusted repository. When combined with Intune Win32 deployments, you get a powerful, scriptable way to deliver applications at scale.

Use cases: - One-off app installs
- Repeatable installs across device groups
- Automated updates when paired with Winget-AutoUpdate


Methods

1) Deploy Winget (App Installer) as a system app

Use the Microsoft Store (New) app type in Intune to install App Installer / DesktopAppInstaller (Winget) as a system app so it exists in C:\Program Files\WindowsApps\... and is available to run in system context.

Intune path: Apps → Add → Windows → Microsoft Store (new) → search App Installer

Why system context?

Winget needs to run without a logged-in user for silent installs at scale.
Deploying App Installer via the Store ensures DesktopAppInstaller is present and accessible to system-level processes.


Workflow: 1. Create PowerShell scripts: install_<pkg>.ps1, uninstall_<pkg>.ps1, detection_<pkg>.ps1 (see templates below).
2. Package them into .intunewin with Microsoft Win32 Content Prep Tool.
3. Upload to Intune as Windows app (Win32) and set install/uninstall commands + detection.


Scripts (template)

Replace PACKAGE_ID with the ID you get from winget search <query> (e.g., 7zip.7zip or GitHub.cli).

Template: detection script

detection.PACKAGE_ID.ps1

# detection.PACKAGE_ID.ps1
# Exits 0 if package is present, 1 otherwise

param(
    [string]$PackageId = 'PACKAGE_ID'
)

# Resolve winget path (App Installer location)
$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" -ErrorAction SilentlyContinue
if ($ResolveWingetPath) {
    $WingetPath = $ResolveWingetPath[-1].Path
    $Winget = Join-Path $WingetPath 'winget.exe'
} else {
    # Fallback to PATH
    $Winget = 'winget'
}

try {
    $output = & $Winget list --id $PackageId 2>$null
    if ($output -match $PackageId) {
        Write-Host "Found $PackageId"
        exit 0
    } else {
        Write-Host "Not Found: $PackageId"
        exit 1
    }
} catch {
    Write-Host "Error running winget: $_"
    exit 1
}

Template: install script

install.PACKAGE_ID.ps1

# install.PACKAGE_ID.ps1
param(
    [string]$PackageId = 'PACKAGE_ID'
)

$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" -ErrorAction SilentlyContinue
if ($ResolveWingetPath) {
    $WingetPath = $ResolveWingetPath[-1].Path
    $Winget = Join-Path $WingetPath 'winget.exe'
} else {
    $Winget = 'winget'
}

try {
    # Example flags for unattended install:
    # --silent, --force, --accept-package-agreements, --accept-source-agreements, --exact
    & $Winget install --id $PackageId --silent --force --accept-package-agreements --accept-source-agreements --exact | Out-Null
    Write-Host "Install command exited with code $LASTEXITCODE"
    exit $LASTEXITCODE
} catch {
    Write-Error "Install failed: $_"
    exit 1
}

Template: uninstall script

uninstall.PACKAGE_ID.ps1

# uninstall.PACKAGE_ID.ps1
param(
    [string]$PackageId = 'PACKAGE_ID'
)

$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" -ErrorAction SilentlyContinue
if ($ResolveWingetPath) {
    $WingetPath = $ResolveWingetPath[-1].Path
    $Winget = Join-Path $WingetPath 'winget.exe'
} else {
    $Winget = 'winget'
}

try {
    & $Winget uninstall --id $PackageId --silent --force --accept-source-agreements | Out-Null
    Write-Host "Uninstall command exited with code $LASTEXITCODE"
    exit $LASTEXITCODE
} catch {
    Write-Error "Uninstall failed: $_"
    exit 1
}


Packaging & Intune settings

Prepare .intunewin

Use Microsoft Win32 Content Prep Tool:

IntuneWinAppUtil.exe -c "C:\Path\To\PackageFolder" -s "install.PACKAGE_ID.ps1" -o "C:\Output"
- PackageFolder contains your 3 scripts and any helpers.
- The tool creates yourpackage.intunewin for upload.

Intune App configuration (in Admin Center)

  • App type: Windows app (Win32)

Install command

powershell.exe -ExecutionPolicy Bypass -File .\install.PACKAGE_ID.ps1

Uninstall command

powershell.exe -ExecutionPolicy Bypass -File .\uninstall.PACKAGE_ID.ps1

Detection rule - Type: Use a custom detection script → upload detection.PACKAGE_ID.ps1
- Run script as 32-bit process on 64-bit clients: No (unless required)
- Enforce script signature check and run script silently: optional — recommended for production (see signing section)

Requirements: Windows 10/11, architecture x64, minimum build number, etc.
Assignment: target device groups; start with a pilot group.


Detection & Error Handling

Detection rules

Reliable detection prevents repeated reinstalls. You can:
- Use the PowerShell script above (exit codes: 0 OK, non-zero fail)
- or use registry-based detection (when known keys exist)
- or file existence checks for specific executable paths

Error handling / logging

Write logs to C:\ProgramData\IntuneLogs\:

$LogPath = "C:\ProgramData\IntuneLogs\winget_install.log"
"[$(Get-Date)] Installing $PackageId" | Out-File -FilePath $LogPath -Append
# on error:
"[$(Get-Date)] Error: $_" | Out-File -FilePath $LogPath -Append
Surface exit codes correctly — Intune interprets non-zero as failure.


Trusted Sources & Why Winget

Why source trust matters

Winget uses sources (Microsoft Community Repository, private repos). Packages must be from trusted sources because:
- Signed packages reduce supply-chain risk.
- Source validation prevents man-in-the-middle attacks or malicious packages.
- Intune + Winget together allow central governance over which sources devices can access.

Winget advantages

  • Modern package management — similar to apt/choco/homebrew.
  • Lightweight — no need to host large MSI/EXE assets.
  • Versioning & updates — easier to maintain and automate.
  • Scriptable — integrates cleanly with PowerShell and automation tooling.

How to verify sources

winget source list
- Use a private/internal winget source for internal packages (recommended for internal builds).
- Enforce source agreements where required.


Example: How to find the PACKAGE_ID

Search:

winget search github.cli

Example output:

Name         Id           Version  Source
----------------------------------------------
GitHub CLI   GitHub.cli   2.81.0   winget
Use the Id column as PACKAGE_ID for your scripts (e.g., GitHub.cli).


Winget-AutoUpdate (optional)

Integrate WAU to keep packages patched:

  • Deploy WAU as a scheduled task / service via Intune.
  • Control update frequency and whitelist/blacklist packages.
  • WAU can run in system context and call winget upgrade --all with filters.

Repo: https://github.com/Romanitho/Winget-AutoUpdate


If your org enforces script signature checks: - Sign your PowerShell scripts with a code-signing certificate trusted by endpoints.
- In Intune, set Enforce script signature check and run script silently to Yes when uploading detection scripts.
- If you do not have a corporate CA, rotate to a private PKI or use Azure Key Vault + certificate provisioning.

Basic signing (dev/test):

Set-AuthenticodeSignature -FilePath .\install.PACKAGE_ID.ps1 -Certificate (Get-ChildItem Cert:\CurrentUser\My\THUMBPRINT)


TL;DR

1) Use winget for lightweight installs.
2) Wrap installs/uninstalls in PowerShell scripts.
3) Package into .intunewin and upload to Intune.
4) Use detection scripts to validate installs.
5) Prefer trusted/managed winget sources; sign scripts for production.

Template usage: run winget search <app> → replace PACKAGE_ID in the three scripts → package & deploy via Intune.


Ready-to-copy filenames & Intune commands

Files (examples)

install.PACKAGE_ID.ps1
uninstall.PACKAGE_ID.ps1
detection.PACKAGE_ID.ps1

Intune Install command

powershell.exe -ExecutionPolicy Bypass -File .\install.PACKAGE_ID.ps1

Intune Uninstall command

powershell.exe -ExecutionPolicy Bypass -File .\uninstall.PACKAGE_ID.ps1

Detection - Use custom detection script (detection.PACKAGE_ID.ps1)
- Do not run as 32-bit process on 64-bit clients (unless required)
- Consider enforcing script signature checks in production


Join the Discussion

Got a question, idea, or a better way to do it? Drop it below — I read every comment and update guides based on real-world feedback.

Add something useful. Ask good questions. Help someone else learn.