How to Use Windows Package Manager (winget) on Windows Server 2022
winget (Windows Package Manager) is Microsoft’s official command-line package manager for Windows. It allows you to search, install, upgrade, remove, and configure software packages from a curated repository of thousands of applications. While winget was originally designed as a consumer-facing tool on Windows 10 and 11, it can be installed and used on Windows Server 2022 with some additional steps, making it a useful tool for server provisioning and software management.
Installing winget on Windows Server 2022
Windows Server 2022 does not include winget by default. It is distributed as part of the App Installer package from the Microsoft Store. Since Windows Server 2022 typically does not have the Store configured or available, winget must be installed manually via the Microsoft Store’s underlying package infrastructure or by downloading the MSIX bundle directly.
The recommended approach for server environments is to download the App Installer MSIX bundle from the GitHub releases page of the winget-cli repository:
# Download the latest App Installer MSIX bundle
# Check https://github.com/microsoft/winget-cli/releases for the current version
$wingetVersion = "v1.8.1911"
$msixUrl = "https://github.com/microsoft/winget-cli/releases/download/$wingetVersion/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
$msixPath = "$env:TEMPAppInstaller.msixbundle"
Invoke-WebRequest -Uri $msixUrl -OutFile $msixPath
# Install the MSIX bundle (requires PowerShell 5.1+)
Add-AppxPackage -Path $msixPath
On Windows Server 2022, you may also need the VCLibs dependency package:
# Install required VCLibs dependency
$vcLibsUrl = "https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx"
$vcLibsPath = "$env:TEMPVCLibs.appx"
Invoke-WebRequest -Uri $vcLibsUrl -OutFile $vcLibsPath
Add-AppxPackage -Path $vcLibsPath
After installation, open a new PowerShell window and verify:
winget --version
If winget is not found, locate the executable path and add it to PATH:
# Find winget executable location
$wingetPath = (Get-Command winget -ErrorAction SilentlyContinue).Source
if (-not $wingetPath) {
$wingetPath = Get-ChildItem "$env:LOCALAPPDATAMicrosoftWindowsApps" -Filter "winget.exe" -Recurse |
Select-Object -First 1 -ExpandProperty FullName
Write-Host "winget found at: $wingetPath"
}
Accepting the EULA (First Run)
On first run, winget requires acceptance of the source agreement for the Microsoft Store and winget-pkgs repository. In automated scripts, bypass this interactively:
# Accept the source agreements non-interactively
winget source update --accept-source-agreements
# Or pass the flag per command
winget search git --accept-source-agreements
Searching for Packages with winget search
The winget search command queries the configured sources (by default, the winget community repository at github.com/microsoft/winget-pkgs) for packages matching the query.
# Search by name (partial match)
winget search nodejs
# Search for an exact match
winget search --exact --id OpenJS.NodeJS
# Search in a specific source
winget search git --source winget
# Filter by moniker (short name)
winget search --moniker git
# Search and output as JSON for scripting
winget search nodejs --output json
Each package in winget has a unique identifier in the format Publisher.PackageName (e.g., Git.Git, OpenJS.NodeJS, Microsoft.VisualStudioCode). Prefer searching by ID for scripts to avoid ambiguity.
Installing Packages with winget install
# Install by package ID (recommended for scripts)
winget install --id Git.Git
# Install without prompting for confirmation
winget install --id Git.Git --silent
# Accept license agreements automatically
winget install --id Git.Git --silent --accept-package-agreements --accept-source-agreements
# Install a specific version
winget install --id OpenJS.NodeJS --version 20.14.0
# Install to a custom location (if the package supports it)
winget install --id Git.Git --location "D:ToolsGit"
# Install multiple packages in a loop from a list
@("Git.Git", "OpenJS.NodeJS.LTS", "Notepad++.Notepad++") | ForEach-Object {
winget install --id $_ --silent --accept-package-agreements --accept-source-agreements
}
The --silent flag suppresses the installer UI. Combined with --accept-package-agreements and --accept-source-agreements, installations become fully non-interactive — critical for automated server provisioning scripts.
Upgrading Packages with winget upgrade
# List all packages with available upgrades
winget upgrade
# Upgrade a specific package
winget upgrade --id Git.Git
# Upgrade all packages with available updates
winget upgrade --all --silent --accept-package-agreements --accept-source-agreements
# Upgrade all except packages that require user interaction
winget upgrade --all --include-unknown
# Dry run - preview upgrades without installing
winget upgrade --all --include-unknown --no-upgrade
The --include-unknown flag includes packages whose installed version winget could not detect (common with some MSI-based applications). Use it when winget upgrade --all misses packages you know are outdated.
Listing Installed Packages with winget list
winget list shows all software detected on the system, including packages not installed by winget. It reads from the Windows installed applications registry, so it captures MSI, MSIX, and some EXE-installed applications.
# List all installed software
winget list
# Filter by name
winget list --name "Node"
# Filter by package ID
winget list --id Git.Git
# Output as JSON
winget list --output json
# Show packages that have updates available
winget list --upgrade-available
Uninstalling Packages with winget uninstall
# Uninstall by package ID
winget uninstall --id Git.Git
# Uninstall silently
winget uninstall --id Git.Git --silent
# Uninstall by display name
winget uninstall --name "Git"
# Uninstall all versions matching a name
winget uninstall --name "Microsoft Visual C++ 2015" --all-versions
Getting Package Details with winget show
# Show detailed information about a package
winget show --id Git.Git
# Show all available versions of a package
winget show --id OpenJS.NodeJS --versions
# Show package in JSON format
winget show --id Git.Git --output json
The winget show output includes: package ID, publisher, version, description, homepage, license, installer type (MSI/MSIX/EXE/ZIP), installer URL, installer SHA256 hash, and system requirements. This information helps verify a package before installing it in a security-sensitive environment.
Exporting Installed Apps with winget export
winget export creates a JSON file listing all winget-managed packages currently installed. This export file serves as a manifest for reproducing the same software stack on another server.
# Export installed packages to JSON
winget export --output C:server-packages.json
# Export with package versions included
winget export --output C:server-packages.json --include-versions
# View the exported file structure
Get-Content C:server-packages.json | ConvertFrom-Json |
Select-Object -ExpandProperty Sources |
ForEach-Object { $_.Packages } |
Select-Object PackageIdentifier, Version
A typical export file looks like this:
{
"$schema": "https://aka.ms/winget-packages.schema.2.0.json",
"CreationDate": "2026-05-17T10:00:00.000-00:00",
"Sources": [
{
"Packages": [
{ "PackageIdentifier": "Git.Git", "Version": "2.44.0" },
{ "PackageIdentifier": "OpenJS.NodeJS.LTS", "Version": "20.14.0" },
{ "PackageIdentifier": "Notepad++.Notepad++" }
],
"SourceDetails": {
"Argument": "https://cdn.winget.microsoft.com/cache",
"Identifier": "Microsoft.Winget.Source_8wekyb3d8bbwe",
"Name": "winget",
"Type": "Microsoft.PreIndexed.Package"
}
}
]
}
Importing Packages with winget import
winget import reads a JSON export file and installs all the packages listed in it. This enables one-command provisioning of a new server to match an existing configuration.
# Import and install all packages from an export file
winget import --import-file C:server-packages.json
# Import silently, accepting all agreements
winget import `
--import-file C:server-packages.json `
--accept-package-agreements `
--accept-source-agreements
# Import but ignore unavailable packages (don't fail if a package is not found)
winget import `
--import-file C:server-packages.json `
--ignore-unavailable `
--accept-package-agreements `
--accept-source-agreements
Configuring winget Sources
winget supports multiple package sources. The default source is the Microsoft winget-pkgs repository. You can add, remove, or reset sources.
# List configured sources
winget source list
# Update all sources (refresh package metadata)
winget source update
# Add a custom source
winget source add --name "internal" --arg "https://nexus.corp.local/winget/" --type "Microsoft.Rest"
# Remove a source
winget source remove --name "internal"
# Reset to default sources
winget source reset --force
winget in Corporate Environments: Microsoft Store Requirements
winget’s App Installer package is technically distributed through the Microsoft Store. On Windows Server 2022, this creates friction because the Store application is not present in server SKUs. The manual MSIX installation method described earlier bypasses this requirement.
For air-gapped or proxy-restricted servers, additional considerations apply. winget downloads installer packages at install time from URLs specified in the package manifest. These URLs point to the software vendor’s CDN or the winget CDN, so outbound HTTPS access is required for each package installation.
Configure WinHTTP proxy settings (which winget uses via WinINet) for corporate proxy environments:
# Configure system proxy (used by winget)
netsh winhttp set proxy proxy.corp.local:8080
# Or use per-user proxy via Internet Explorer settings
Set-ItemProperty -Path "HKCU:SoftwareMicrosoftWindowsCurrentVersionInternet Settings" `
-Name ProxyServer -Value "proxy.corp.local:8080"
Set-ItemProperty -Path "HKCU:SoftwareMicrosoftWindowsCurrentVersionInternet Settings" `
-Name ProxyEnable -Value 1
For fully air-gapped environments, winget is less suited than Chocolatey with an internalized repository. winget does not natively support storing installer binaries in a local repository — it always fetches them from the URL specified in the package manifest.
Scripting winget Installs with PowerShell
winget exits with code 0 on success. PowerShell scripts can check exit codes and handle errors appropriately:
function Install-WingetPackage {
param(
[string]$PackageId,
[string]$Version = $null
)
$args = @(
"install",
"--id", $PackageId,
"--silent",
"--accept-package-agreements",
"--accept-source-agreements"
)
if ($Version) {
$args += "--version"
$args += $Version
}
Write-Host "Installing $PackageId..."
$result = & winget @args
if ($LASTEXITCODE -eq 0) {
Write-Host "$PackageId installed successfully." -ForegroundColor Green
} elseif ($LASTEXITCODE -eq -1978335189) {
# 0x8A150023 - Package already installed
Write-Host "$PackageId is already installed." -ForegroundColor Yellow
} else {
Write-Warning "$PackageId installation failed with exit code: $LASTEXITCODE"
}
}
# Example server provisioning script
Install-WingetPackage -PackageId "Git.Git" -Version "2.44.0"
Install-WingetPackage -PackageId "OpenJS.NodeJS.LTS"
Install-WingetPackage -PackageId "Notepad++.Notepad++"
Install-WingetPackage -PackageId "7zip.7zip"
Common winget exit codes:
# Exit code reference
# 0 = Success
# -1978335189 = APPINSTALLER_CLI_ERROR_PACKAGE_ALREADY_INSTALLED
# -1978335215 = APPINSTALLER_CLI_ERROR_NO_APPLICABLE_INSTALLER
# -1978335210 = APPINSTALLER_CLI_ERROR_PACKAGE_IS_PINNED
# -1978334971 = APPINSTALLER_CLI_ERROR_SOURCE_NOT_FOUND
winget vs Chocolatey: Comparison
Package coverage: The winget community repository (winget-pkgs on GitHub) has over 20,000 packages as of 2026. Chocolatey community has over 9,000. Both cover the most common developer and administrative tools, but winget’s repository is growing faster due to Microsoft’s backing and direct publisher submissions.
Corporate/offline support: Chocolatey has significantly better support for offline and air-gapped environments through package internalization (Chocolatey Business) and self-hosted NuGet repositories. winget’s MSIX-based architecture requires live internet access or a REST-based package source, which is harder to self-host.
Scripting and automation: Both tools work well in PowerShell scripts. Chocolatey’s longer history means more examples, community modules, and configuration management integrations (Puppet, Chef, Ansible winrm). winget is simpler to install and requires no bootstrap script.
Custom packages: Creating custom packages is more mature and documented in Chocolatey, with a full NuGet packaging workflow, checksum verification, and install/uninstall script hooks. winget’s custom source support is limited to the Microsoft.Rest source type and is less commonly used.
On Windows Server: Chocolatey installs cleanly on Windows Server 2022 with no dependencies. winget requires manual MSIX deployment due to the missing Microsoft Store. For production server automation, Chocolatey is currently the more reliable choice. winget is better suited for developer workstation scenarios and environments already standardized on Microsoft tooling.
Keeping winget Updated
# Check the current winget version
winget --version
# Update winget itself via winget
winget upgrade --id Microsoft.AppInstaller --silent
# Or update App Installer via PowerShell (download latest from GitHub)
$latestRelease = Invoke-RestMethod "https://api.github.com/repos/microsoft/winget-cli/releases/latest"
$msixUrl = ($latestRelease.assets | Where-Object { $_.name -like "*.msixbundle" }).browser_download_url
$msixPath = "$env:TEMPAppInstaller-latest.msixbundle"
Invoke-WebRequest -Uri $msixUrl -OutFile $msixPath
Add-AppxPackage -Path $msixPath
Summary
winget on Windows Server 2022 requires manual installation via MSIX bundle since the Microsoft Store is unavailable on server SKUs. Once installed, it provides a clean command-line interface for searching, installing, upgrading, and exporting software inventories. Use winget export and winget import to document and replicate software stacks across servers. For corporate environments with proxy restrictions, configure WinHTTP proxy settings. In air-gapped or complex enterprise scenarios, Chocolatey with a self-hosted repository offers more mature offline and custom packaging support, while winget excels in internet-connected environments where simplicity and Microsoft ecosystem integration are priorities.