WinGet, the Windows Package Manager CLI, brings simple, scriptable installs, upgrades, and uninstalls to Windows. In enterprise and team environments, the most powerful capability isn’t just consuming public catalogs—it’s running your own private WinGet source. A private repository gives you full control over what software is available, how it’s packaged, and when updates are released. In this hands‑on guide you’ll learn exactly how to host your own WinGet repository, add it as a source, publish packages, automate updates, and troubleshoot issues. You’ll get practical examples, ready‑to‑use commands, YAML samples, and scripts you can adapt for your environment.
Overview of the Use Case (en heading H2)
What a private WinGet source does, in plain language
- A private WinGet source is your organization’s own catalog of packages that users access via the WinGet CLI. It hosts package manifests (YAML) and references installers you control (internal mirrors or vendor URLs).
- Users can search, install, upgrade, and uninstall software from your private catalog using the same familiar WinGet commands they use for the public sources—except now the catalog is curated by you.
Why this matters
- Security and compliance: Only approved software is available. You can mirror installers internally, hash them, and gate access behind your security perimeter.
- Reliability and performance: Faster installs/updates from your LAN/CDN; no dependency on public service uptime.
- Consistency and automation: Pin versions, enforce silent install flags, and coordinate rollouts via CI/CD, Intune, or device management tools.
Common scenarios where a private WinGet repository shines
- Fresh device provisioning: Use a curated baseline of apps during imaging or autopilot onboarding.
- Bulk updates and maintenance: Run one command to upgrade all apps across hundreds or thousands of devices.
- CI/CD automation: Publish new versions when your product releases; automatically update manifests.
- Lab, VDI, and offline/low‑bandwidth deployments: Mirror installers behind the firewall or on an internal share.
- Regulated environments: Maintain auditable manifests and hashes to meet change‑control requirements.
Quick Reference Table (en heading H2)
| Command | Purpose | Example Output |
|---|---|---|
| winget –info | Show WinGet version and system info | Windows Package Manager v1.6.x…; System architecture: x64 |
| winget source list | List configured sources | Name Arg Type; winget https://… Microsoft.PreIndexed; msstore https://… Microsoft.Store; PrivateRepo https://repo.contoso.local/api Microsoft.Rest |
| winget source add –name PrivateRepo –type Rest –arg https://repo.contoso.local/api | Add your private REST source | Added source: PrivateRepo |
| winget source update –name PrivateRepo | Refresh catalog metadata | Updating source: PrivateRepo; Done |
| winget source reset –force | Reset sources to defaults (repair) | Resetting sources… Done |
| winget search myapp –source PrivateRepo | Search for a package in your repo | Name Id Version Source; Contoso MyApp Contoso.MyApp 1.2.3 PrivateRepo |
| winget show Contoso.MyApp –source PrivateRepo | Show manifest details | Id: Contoso.MyApp; Version: 1.2.3; InstallerType: msi; InstallerUrl: https://… |
| winget install –id Contoso.MyApp –source PrivateRepo –silent | Install from your repo | Successfully installed |
| winget upgrade –source PrivateRepo –all –silent | Upgrade all packages from your repo | No applicable upgrades found OR list of upgraded packages |
| winget validate –manifest .\manifests\Contoso.MyApp.yaml | Validate YAML manifest | Manifest validation succeeded |
| winget hash .\MyApp-x64.msi | Compute SHA256 for manifest | SHA256: ABCDEF…1234 |
| winget export -o .\baseline.json –include-versions | Export installed apps | Wrote export file to .\baseline.json |
| winget import -i .\baseline.json –source PrivateRepo –accept-package-agreements –accept-source-agreements | Reinstall baseline from your repo | Installing packages listed in baseline.json… |
Key Concepts and Prerequisites (en header H2)
Key concepts
- Source types: WinGet can use different source types. For private hosting, the recommended model is a REST source (Type: Microsoft.Rest), which supports search, show, install, and upgrade.
- Manifests: YAML files describe packages—IDs, versions, installer URLs, checksums, silent switches, dependencies, etc.
- Installers: Actual binaries (MSI, EXE, MSIX, ZIP, portable) hosted at internal or vendor URLs. WinGet downloads and verifies them via SHA256.
- Search/upgrade integration: With a REST source, your packages integrate into winget search/upgrade workflows just like public sources.
Prerequisites
- WinGet (Windows Package Manager) installed via App Installer (Microsoft Store) on Windows 10 1809+ or Windows 11. Recommended WinGet CLI v1.4+ (ideally 1.6+).
- PowerShell available (5.1+ or PowerShell 7+).
- Administrative rights for system-wide installs and source configuration on managed devices (recommended).
- HTTPS endpoint for your private REST service (TLS certificate configured).
- Storage for manifests and installers (Git repo + CI/CD + object storage/CDN or web server).
How to check your WinGet version
- Command: winget –info
- You should see Windows Package Manager v1.4.x or higher. If not, update the App Installer package from the Microsoft Store or your enterprise channel.
Step-by-Step Guide (en heading H2)
This guide uses the recommended REST source model. You’ll deploy a REST API, create manifests, publish them, and connect clients.
Option A (recommended): Host a REST source
H3: 1) Plan your repository and network architecture
- Choose your host: Windows Server with IIS/Kestrel, Linux with Nginx/Apache, or a managed PaaS (App Service). The REST service is a standard HTTPS API.
- Storage:
- Manifests: Keep them in a Git repository for version control.
- Installers: Prefer internal object storage, NAS, or web server under your control. Mirror vendor binaries if allowed and keep checksums updated.
- Access control:
- Internal only: Restrict via firewall/VPN.
- Authenticated: Reverse proxy with auth (e.g., mTLS, OAuth, header‑based auth). You can place an API gateway in front.
- DNS and TLS:
- Create a DNS name like repo.contoso.local or packages.contoso.com.
- Install a trusted TLS cert on the endpoint.
H3: 2) Deploy the WinGet REST source
- Use the official reference implementation for the Windows Package Manager REST source (often called “winget-rest-source”). It’s a .NET web API that implements the WinGet source contract.
- Deployment outline (generic)
- Prepare a host (Windows or Linux) with .NET 6+ runtime (or container host).
- Publish the REST service:
- If using source code: dotnet publish -c Release, then host behind IIS/Kestrel or systemd.
- If using a container image: run it behind a reverse proxy with TLS.
- Configure environment variables or appsettings for:
- Base URL (e.g., https://repo.contoso.local/api)
- Storage/metadata backend for packages and versions (database or files, depending on implementation)
- Read vs. write permissions (set write to CI/CD only; read for clients)
- Test health: curl https://repo.contoso.local/api/information
Notes:
- The REST schema exposes endpoints for searching packages, retrieving manifests, and version queries. Make sure the app responds with 200 OK on /information and supports the manifest search endpoints.
H3: 3) Create a package manifest (YAML)
You can write manifests manually or use a helper (e.g., the wingetcreate tool) to scaffold them. Below is a full singleton YAML example with inline comments.
Example: .\manifests\Contoso.MyApp.yaml
A simple singleton manifest for WinGet
Save as: Contoso.MyApp.yaml (for demonstration; production repos often use multi-file manifests)
Id: Contoso.MyApp # Unique ID (Publisher.App)
Version: 1.2.3 # Semantic version
Name: Contoso MyApp
Publisher: Contoso Ltd.
Author: Contoso Ltd.
License: Proprietary
LicenseUrl: https://contoso.example.com/myapp/license
Homepage: https://contoso.example.com/myapp
AppMoniker: myapp
Description: “Contoso MyApp is a sample enterprise tool.”
Tags:
- contoso
- myapp
- enterprise
ReleaseNotes: “Bug fixes and performance improvements.”
ReleaseNotesUrl: https://contoso.example.com/myapp/releases/1.2.3
Define how to install (MSI example)
InstallerType: msi # exe | msi | msix | zip | inno | nullsoft | burn | portable
Scope: machine # machine | user
InstallModes:
- silent
- silentWithProgress
InstallerSwitches: # Silent flags are critical for automation
Silent: /qn
SilentWithProgress: /qb
Custom: TRANSFORMS=MyApp.mst
If MSI, include ProductCode to help WinGet track upgrades
ProductCode: ‘{12345678-90AB-CDEF-1234-567890ABCDEF}’
UpgradeBehavior: install
Expected return codes (optional but recommended for robust automation)
InstallerSuccessCodes:
- 3010 # MSI: restart required
Define installers for each architecture/locale you support
Installers:
- Architecture: x64
InstallerUrl: https://repo.contoso.local/content/myapp/1.2.3/MyApp-x64.msi
InstallerSha256: ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890
SignatureSha256: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF # optional if you sign
NestedInstallerType: none
AppsAndFeaturesEntries:- DisplayName: Contoso MyApp
Publisher: Contoso Ltd.
ProductCode: ‘{12345678-90AB-CDEF-1234-567890ABCDEF}’
InstallerType: msi
- DisplayName: Contoso MyApp
Commands:
- myapp
Manifest metadata
ManifestType: singleton
ManifestVersion: 1.6.0
Best practices for authoring manifests
- Always set InstallerSha256 for every installer. Compute it with: winget hash .\MyApp-x64.msi
- Use Scope: machine for enterprise apps needing admin install; pair with –silent in your scripts.
- Provide ProductCode (MSI) so WinGet can detect installed versions and upgrades.
- Include correct InstallerSwitches for silent/silentWithProgress. For MSI: /qn or /qb; for EXE, consult vendor docs.
H3: 4) Validate your manifest locally
Use WinGet’s validation tools before publishing:
Validate YAML schema and basic rules
winget validate –manifest .\manifests\Contoso.MyApp.yaml
Compute and verify file hashes
winget hash .\MyApp-x64.msi
Make sure the SHA256 in the manifest matches the installer file you intend to host.
H3: 5) Publish manifests and installers to your repository
- Upload installers to your internal web server or object store (the URL used in InstallerUrl).
- Publish the manifest(s) to the storage backend that your REST service uses, or push them to a Git repo and run a pipeline that synchronizes manifests into the REST source’s store.
- Common CI/CD approach:
- When a release is tagged, build artifacts (MSI/EXE).
- Compute SHA256, update YAML manifest automatically.
- Validate manifests.
- Publish installers to https://repo.contoso.local/content/… and push manifests to the REST backend.
- Trigger a cache refresh (if your implementation has a reindex step).
H3: 6) Add the private source on clients
On any device that should consume your repo:
Optional: verify WinGet availability
winget –info
Add your private REST source (name and URL to your service)
winget source add –name PrivateRepo –type Rest –arg https://repo.contoso.local/api
Confirm it shows up
winget source list
Update metadata (good practice after adding)
winget source update –name PrivateRepo
H3: 7) Install, search, upgrade from your private source
Try these end‑to‑end commands:
Search for a package
winget search myapp –source PrivateRepo
Show details (verify manifest fields)
winget show Contoso.MyApp –source PrivateRepo
Install silently (perfect for automation)
winget install –id Contoso.MyApp –source PrivateRepo –silent –accept-package-agreements –accept-source-agreements
Upgrade from your repo (all apps your source tracks)
winget upgrade –source PrivateRepo –all –silent –accept-package-agreements –accept-source-agreements
Uninstall (if supported)
winget uninstall –id Contoso.MyApp
Option B: Use local manifests without a source (quick and offline-friendly)
If you don’t need search/upgrade integration and just want repeatable installs:
- Place YAML manifests and installers on a file share.
- Install directly from YAML:
winget install -m \fileserver\manifests\Contoso.MyApp.yaml –silent –accept-package-agreements
This is handy for offline or ad‑hoc scenarios, but you won’t get source‑backed search/upgrade.
Troubleshooting (en heading H2)
Common errors and how to fix them
H3: Hash mismatch (InstallerSha256 mismatch)
Symptoms: WinGet errors that the installer hash does not match the manifest.
-
Causes: Installer file changed, wrong URL, or incorrect SHA.
-
Fix:
-
Download the exact file referenced by InstallerUrl and compute its hash:
winget hash .\MyApp-x64.msi
-
Update InstallerSha256 in the YAML to the correct value.
-
Re‑publish the manifest and update source metadata:
winget source update –name PrivateRepo
-
H3: Multiple installers found / ambiguous match
Symptoms: Search or install finds multiple packages or architectures.
-
Fix:
-
Specify the Id and –exact if needed:
winget install –id Contoso.MyApp –source PrivateRepo –exact –silent
-
Ensure your manifest defines Architecture for each installer and avoid overlapping criteria.
-
Include ProductCode (MSI) and consistent naming to help detection.
-
H3: Source not responding / index errors
Symptoms: winget source update fails; search returns no results.
-
Fix:
-
Verify endpoint health: curl https://repo.contoso.local/api/information
-
Check TLS cert validity and firewall rules.
-
Refresh sources:
winget source update –name PrivateRepo
-
As a last resort, reset sources:
winget source reset –force
-
Then re‑add your source.
-
H3: 401/403 Unauthorized when accessing a private source
- Fix:
- Confirm the device is on the allowed network or VPN.
- If you protect the endpoint behind an auth proxy, configure client trust (certs, device auth) or allow anonymous GET for read‑only package queries.
- Validate time skew and TLS configuration.
H3: Install fails silently in automation
- Fix:
- Ensure correct InstallerSwitches. For MSI, use /qn for true silent; many EXE installers need vendor‑specific silent flags.
- Add –silent –accept-package-agreements –accept-source-agreements to non‑interactive scripts.
- Check exit codes. Add InstallerSuccessCodes for non‑zero “success” codes like 3010 (restart required).
H3: Upgrades not detected
-
Fix:
-
Verify Version increments in manifests.
-
For MSI, ensure ProductCode reflects upgrades (same or changed depending on MSI scheme) and that UpgradeCode/ProductVersion rules are correct.
-
Run:
winget upgrade –source PrivateRepo
-
Automation Tips (en heading H2)
H3: PowerShell bootstrap for devices
Use a single script to configure the source and install a baseline.
Example: Add the source idempotently and install a baseline list
Add private source if missing
$srcName = “PrivateRepo”
$srcUrl = “https://repo.contoso.local/api”
$exists = winget source list | Select-String -SimpleMatch $srcName
if (-not $exists) {
winget source add –name $srcName –type Rest –arg $srcUrl
} else {
winget source update –name $srcName
}
Optional: install a baseline set (by Id)
$packages = @(
“Contoso.MyApp”,
“Contoso.Tools.CLI”,
“Contoso.Viewer”
)
foreach ($pkg in $packages) {
winget install –id $pkg –source $srcName –silent –accept-package-agreements –accept-source-agreements
}
H3: Scheduled Task to auto‑upgrade nightly
- Save a script (Upgrade-PrivateRepo.ps1):
winget source update –name PrivateRepo
winget upgrade –source PrivateRepo –all –silent –accept-package-agreements –accept-source-agreements
- Create a scheduled task to run as SYSTEM or with admin rights at 3 AM daily.
H3: Intune device script integration
- Push a PowerShell script that:
- Adds the PrivateRepo source.
- Installs required packages with –silent.
- Optionally runs a periodic winget upgrade –all from your source.
- Scope devices via dynamic groups to control rollout waves.
H3: CI/CD pipeline to publish packages
- On release:
- Build your MSI/EXE artifacts.
- Compute SHA256: winget hash path\to\installer.ext
- Update manifest YAML (bump Version, URLs, hashes).
- Validate: winget validate –manifest path\to\yaml
- Publish installers to your internal content store.
- Publish manifest(s) to the REST source storage.
- Trigger your REST source to refresh (if your implementation caches results).
H3: Offline and low‑bandwidth sites
- Mirror installers to a local file server in each site and point InstallerUrl to the local mirror (per site DNS).
- Pre‑stage downloads overnight using a management script.
- For completely offline segments, use local YAML with winget install -m path\to\yaml.
Best Practices (en heading H2)
H3: Governance and security
- Only host trusted installers and verify their hashes. Always update InstallerSha256 after any rebuild.
- Serve your REST source over HTTPS with a valid certificate.
- Control access using network ACLs, VPN, or an auth‑enabled reverse proxy.
- Separate read (client) and write (publisher) paths; CI/CD should be the only writer.
H3: Manifest quality and consistency
- Use consistent IDs: Publisher.App (e.g., Contoso.MyApp). Don’t rename IDs once in use.
- Keep manifests small and focused. For complex apps, consider multi‑file manifests (installer.yaml, locale.yaml, version.yaml) following WinGet schema guidance.
- Include silent install switches and expected return codes to avoid hung installs in unattended runs.
- Specify Architecture for each installer and provide both x64 and arm64 where applicable.
- Include ProductCode for MSI packages and AppsAndFeaturesEntries to aid detection.
H3: Versioning and pinning
-
Use strict semantic versions and avoid reusing a version number for different binaries.
-
For baselines, export with versions and re‑import to pin:
winget export -o .\baseline.json –include-versions
winget import -i .\baseline.json –source PrivateRepo –accept-package-agreements –accept-source-agreements
H3: Repository hygiene
- Remove or archive deprecated versions after a deprecation window.
- Keep release notes and metadata updated; include ReleaseNotes and ReleaseNotesUrl.
- Test installs in a staging environment before promoting manifests to production.
H3: Operational excellence
- Monitor your REST source health (availability, latency).
- Log package installs and upgrades on endpoints for auditability.
- Document app‑specific switches and post‑install tasks (e.g., licensing) in team runbooks.
Conclusion (en heading H2)
Hosting a private WinGet source gives you reliable, secure, and automated software deployment across Windows fleets. You learned how to:
- Deploy a REST source and secure it behind HTTPS.
- Author high‑quality YAML manifests with correct hashes and silent flags.
- Publish packages and add your source to clients.
- Automate installs and upgrades via PowerShell, Task Scheduler, Intune, or CI/CD.
- Diagnose and fix common issues fast.
Try the commands in this guide on a test machine, starting with winget source add and winget search. With careful manifests and a solid publishing pipeline, WinGet becomes a safe and powerful foundation for managing Windows software at scale.
FAQ Section (en heading H2)
H4: Can I host installers on an internal server and still use WinGet?
Yes. Set InstallerUrl in your manifest to an internal HTTPS endpoint (e.g., https://repo.contoso.local/content/…). Ensure the endpoint is reachable from clients and that InstallerSha256 matches the hosted file. This is a common pattern for bandwidth control and security.
H4: Do I have to use a REST source, or can I install directly from YAML?
You can install directly from local or network YAML using winget install -m path\to\manifest.yaml. However, without a source you won’t get integrated search/upgrade. For a full catalog experience, use a REST source.
H4: How do I handle packages that use custom EXE installers?
Declare InstallerType: exe and provide the correct silent switches under InstallerSwitches. Common examples include /S, /silent, /verysilent, or vendor‑specific flags. Always test unattended installs, and add non‑zero success codes if needed.
H4: How can I pin versions or prevent automatic upgrades?
Export a baseline with versions and re‑import it for consistent deployments:
- winget export -o .\baseline.json –include-versions
- winget import -i .\baseline.json –source PrivateRepo
For strict pinning, avoid running blanket winget upgrade –all on those devices, or curate your repo so only approved versions are present.
H4: What about portable apps and ZIP installers?
WinGet supports portable and zip types. For ZIP, provide extraction behavior using manifest keys appropriate for your schema version. For portable apps, specify Installers with InstallerType: portable, and define the executable and path actions as required by the schema. Always include a valid InstallerSha256 and test silent behavior if applicable.
Appendix: Additional ready‑to‑use snippets (en heading H2)
H3: Verify and re‑publish a new version end‑to‑end
1) Build artifacts and place MyApp-x64.msi at .\dist\MyApp-x64.msi
2) Compute hash
$hash = (winget hash .\dist\MyApp-x64.msi | Select-String ‘SHA256:’ ).ToString().Split()[1]
3) Update manifest (simple example; in CI, edit YAML via a script)
(Get-Content .\manifests\Contoso.MyApp.yaml) -replace ‘Version: .‘,’Version: 1.2.4’ `
-replace ‘InstallerSha256: .‘,”InstallerSha256: $hash” | Set-Content .\manifests\Contoso.MyApp.yaml
4) Validate
winget validate –manifest .\manifests\Contoso.MyApp.yaml
5) Publish installer to your content store and manifest to the REST backend (implementation-specific)
6) Refresh clients’ view
winget source update –name PrivateRepo
H3: Baseline deployment on a new device
Ensure source is present
winget source add –name PrivateRepo –type Rest –arg https://repo.contoso.local/api
Install baseline using a JSON export created earlier
winget import -i \share\baselines\standard.json –source PrivateRepo –accept-package-agreements –accept-source-agreements
H3: Silent install and logging
MSI example with logging
winget install –id Contoso.MyApp –source PrivateRepo –silent –override “/qn /L*v C:\Temp\MyAppInstall.log” –accept-package-agreements
Tip: For MSI packages, you can pass vendor flags via –override. For EXE installers, ensure the switches are correct; combine with –silent for non‑interactive runs.
You now have everything you need to design, deploy, and operate a private WinGet source—from manifests and hosting to automation and troubleshooting. With a bit of upfront setup and good manifest hygiene, WinGet becomes a robust, enterprise‑grade delivery mechanism for your Windows applications.
