Skip to content

Installation Guide for LTSC (and Server OS) #1781

Closed

Description

@Zamiell

Greetings,

As a brand new winget user, it was painful to get up and running with this software.
This is an issue to request that:

  1. Better documentation should exist; please integrate my work below.
  2. The installer should automatically install the require VCLibs dependency, if necessary. If that is not possible for some technical reason, then a missing VSLibs should be detected and the user should be shown a clear and actionable error message. The existing state of affairs is bad UX; no software should be silently failing.
  3. The installer should detect if a license is specified and if it isn't, prevent the software from being installed while simultaneously showing the user the correct command for specifying a license. It doesn't make sense to allow an unlicensed version to be successfully installed when it results in bricked software.
  4. The installer should not return until winget is actually in the path. This leads to broken scripts and hard-to-troubleshoot behavior.

I'll do my part to help document what I know in this issue, and I leave it to others to do a pull request and/or integrate this information. In the meantime, this may be useful to other users searching through the GitHub issues.


How to Install winget on Windows 10 LTSC / Windows 10 IoT / Windows Server

Summary

  • The official README.md file suggests that you should use the Microsoft Store to get winget.
  • However, this is not possible on Windows 10 LTSC, Windows 10 IoT, or Windows Server, because those operating systems do not have the Microsoft Store installed. Furthermore, it is not possible to manually install the Microsoft Store on those operating systems. (Nor would you want to. 😃)
  • In short, the solution is to manually install the msixbundle file from the GitHub releases page.
  • I can verify that the following steps work properly for Windows 10 LTSC 2021, but not other operating systems. With that said, I imagine that the same steps would work.

Compatibility

winget will work on:

  • LTSC 2019 (build 1809)
  • LTSC 2021 (build 21H2)

It isn't compatible with earlier versions of LTSC.

I don't know the specific versions of Windows Server or Windows IoT that it will work on, if any.

Step 1

Add-AppxProvisionedPackage -Online -PackagePath "C:\Microsoft.VCLibs.x64.14.00.Desktop.appx" -SkipLicense
  • Note that instead of using AppxProvisionedPackage here, you could also use AppxPackage. The difference is that:
  • Also note that without this dependency installed, the winget installer will silently fail (without any error/warning messages). Specifically, the "winget.exe" file will not be added to "C:\Users[Username]\AppData\Local\Microsoft\WindowsApps".

Step 2

  • On the GitHub releases page, find the latest version that does not have a "Pre-release" tag. For reference, at the time of this writing, the latest non-pre-release version is v1.1.12653.
  • Download both the "msixbundle" file and the "License1.xml" file. For reference, at the time of this writing, this is "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" and "9c0fe2ce7f8e410eb4a8f417de74517e_License1.xml", respectively.
  • Install it with the following Powershell command in an elevated/administrator shell:
Add-AppxProvisionedPackage -Online -PackagePath "C:\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -LicensePath "C:\9c0fe2ce7f8e410eb4a8f417de74517e_License1.xml"

Now, you should see the "winget.exe" file appear at "C:\Users[Username]\AppData\Local\Microsoft\WindowsApps". Furthermore, it should also be automatically added to your path.

Gotchas

The point at which winget is added to the path seems random. Sometimes, a sleep of 5 seconds works. Other times, I have to restart my whole computer to get it to show up. So your mileage may vary.


Using winget on First Boot

  • Obviously, if you plan to use winget as your primary package manager, you will want to either:
    1. integrate it into the Windows source with DISM, or
    2. install it automatically on the first boot with a PowerShell script
  • (2) is the simpler option, but I would not recommend it, as the winget installer seems to be unreliable. I was not able to get winget to appear in the PATH in post-installation scripts in a consistent way; your mileage may vary.

1) Integrating with DISM (recommended)

If you've used DISM before to e.g. integrate drivers into a Windows installation source, this process is almost exactly the same.

The following is a reference batch script to accomplish this:

rem Mount the Windows installation source
dism /Mount-Wim /WimFile:"C:\MyWindowsSource\sources\install.wim" /Index:1 /MountDir:"C:\mount"

rem Integrate winget
dism /Image:"C:\mount" /Add-ProvisionedAppxPackage /PackagePath:"C:\winget\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" /DependencyPackagePath:"C:\winget\Microsoft.VCLibs.x64.14.00.Desktop.appx" /LicensePath:"C:\winget\9c0fe2ce7f8e410eb4a8f417de74517e_License1.xml" /region=all

rem Save the changes
dism /unmount-wim /mountdir:"C:\mount" /commit

2) Using autounattend.xml + PowerShell (not recommended)

  • The "autounattend.xml" file is the file that you stick inside of a Windows source to automate the install, perform additional registry tweaks, and so on.
  • The "autounattend.xml" file can run arbitrary commands, so if you want it to install winget, you have two main options:
    • You can integrate a PowerShell script into the Windows source itself using DISM, and then execute it directly from "autounattend.xml".
    • Or, you can download a script from the Internet (using e.g. curl) and then execute that. (This is the simplest way, but you may not want your script to be public, or you may not have internet access on first boot, etc.)
  • For reference, here is an "autounattend.xml" file that launches a PowerShell script on first boot. (In real life, you would want to integrate the "SynchronousCommand" section into your existing "autounattend.xml" file that automates all of the rest of the Windows setup and so on, which is outside the scope of this tutorial.)
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
	<settings pass="oobeSystem">
		<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
			<FirstLogonCommands>
				<!--
					The PowerShell script will take a long time to execute,
					but for some reason, Windows will not wait for it to complete,
					and will instead boot as normal. The PowerShell window will be
					visible and will continue to run.
				-->
				<SynchronousCommand wcm:action="add">
					<Order>100</Order>
					<Description></Description>
					<CommandLine>powershell -ExecutionPolicy Unrestricted "C:\Windows\Setup\Scripts\install-winget.ps1"</CommandLine>
				</SynchronousCommand>
			</FirstLogonCommands>
		</component>
	</settings>
</unattend>

install-winget.ps1:

# Install winget
Add-AppxPackage "C:\Windows\Setup\Scripts\winget\Microsoft.VCLibs.x64.14.00.Desktop.appx"
Add-AppxProvisionedPackage -Online -PackagePath "C:\Windows\Setup\Scripts\winget\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -LicensePath "C:\Windows\Setup\Scripts\winget\9c0fe2ce7f8e410eb4a8f417de74517e_License1.xml"

# Sleep for 5 seconds to let winget get into the path because the installer is a buggy mess
# If this does not work, try restarting the entire computer and installing the subsequent software on the next boot
Start-Sleep -s 5

# Install software
winget install --accept-source-agreements --silent --exact --id "Microsoft.VisualStudioCode"
winget install --accept-source-agreements --silent --exact --id "Notepad++.Notepad++"
winget install --accept-source-agreements --silent --exact --id "Git.Git"

Activity

  1. added
    Issue-DocsIt's a documentation issue that really should be on MicrosoftDocs
    on Dec 7, 2021
  2. ghost added
    Needs-TriageIssue needs to be triaged
    on Dec 7, 2021
  3. o-l-a-v commented on Dec 7, 2021

    @o-l-a-v

    Running from system context, what will be the difference of installing the msixbundle using Add-AppxPackage vs. Add-AppxProvisionedPackage?

    I'm looking into doing this from Intune with a Win32 package. Thought following would be sufficient.

    "%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy "Bypass" -NoLogo -NonInteractive -NoProfile -WindowStyle "Hidden" -Command "$null = Add-AppxPackage -Path ".\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle""

    Alternatively if needed, install command will be

    "%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy "Bypass" -NoLogo -NonInteractive -NoProfile -WindowStyle "Hidden" -Command "$null = Add-AppxProvisionedPackage -Online -PackagePath ".\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -LicensePath ".\9c0fe2ce7f8e410eb4a8f417de74517e_License1""

    Edit: Seems first is for user context, while 2nd is system context.

    Edit2: Ended up downloading msixbundle and license xml from this GitHub repo release section. And dependencies as appx from https://store.rg-adguard.net/. With following install script wrapped in *.intunewin.

    Click to view
    #Requires -RunAsAdministrator
    #Requires -Version 5.1
    <#
        .SYNOPSIS
            Installs Microsoft App Installer if version included with this script is newer than the one installed.
    
        .NOTES
            Author:   Olav Rønnestad Birkeland
            Created:  211207
            Modified: 211207
    
        .EXAMPLE
            & $psISE.CurrentFile.FullPath; $LASTEXITCODE
    #>
    
    
    # Input parameters
    [OutputType($null)]
    Param()
    
    
    # PowerShell preferences
    $ErrorActionPreference = 'Stop'
    $InformationPreference = 'Continue'
    $ProgressPreference    = 'SilentlyContinue'
    
    
    # Assets
    $RequiredVersion  = [System.Version] '1.16.12653.0'
    $InstalledVersion = [System.Version](
        Get-AppxPackage -Name 'Microsoft.DesktopAppInstaller' -AllUsers | Sort-Object -Property 'Version' -Descending | Select-Object -First 1 -ExpandProperty 'Version'
    )
    $MsixBundlePath    = [string]((Get-ChildItem -Path $PSScriptRoot -Filter '*.msixbundle' -File).'FullName')
    $LicensePath       = [string]((Get-ChildItem -Path $PSScriptRoot -Filter '*.xml' -File).'FullName')
    $DependenciesPaths = [string[]]((Get-ChildItem -Path $PSScriptRoot -Filter '*.appx' -File).'FullName')
    
    
    # Write information
    Write-Information -MessageData (
        [PSCustomObject]@{
            'RequiredVersion'  = [string] $RequiredVersion
            'InstalledVersion' = [string] $InstalledVersion
            'MsixBundlePath'   = [string] $MsixBundlePath
            'LicensePath'      = [string] $LicensePath
            'DependeciesPaths' = [string] ($DependenciesPaths -join ';')
        } | Format-List | Out-String
    ).Trim()
    
    
    # Failproof
    if ([string]::IsNullOrEmpty($MsixBundlePath)) {
        Throw 'Did not find the *.msixbundle file.'
    }
    if (-not [System.IO.File]::Exists($MsixBundlePath)) {
        Throw ('Path "{0}" does not exist.' -f $MsixBundlePath)
    }
    
    
    # Install
    if ($InstalledVersion -lt $RequiredVersion) {
        Write-Information -MessageData ('Installing v{0} from "{1}".' -f $RequiredVersion, $MsixBundlePath)
        Add-AppxProvisionedPackage -Online -PackagePath $MsixBundlePath -LicensePath $LicensePath -DependencyPackagePath $DependenciesPaths
    }
    else {
        Write-Information -MessageData ('Same or newer version is already installed.')
    }
    
    
    # Exit
    Write-Output -InputObject 'Done.'
    Exit 0
  4. Zamiell commented on Dec 7, 2021

    @Zamiell
    Author

    Edit: Seems first is for user context, while 2nd is system context.

    Good question.

    • I'm not sure if installing VCLibs as user context or system context changes anything. If so, it should be documented.
    • I'm not sure if installing winget as user context or system context changes anything. If so, it should be documented.

    For now, I've added this information to the tutorial and assumed that the user wants to install both of them in a system context.

  5. mariobrostech commented on Dec 7, 2021

    @mariobrostech

    Hi, thanks for taking the time to write such a detailed post on this! I've run into this issue in the past, and when I did, I opted to integrate winget directly into the Windows install image using DISM and the Windows 10 ADK to re-pack my changes into an updated ISO file. You can read the thread that explains how I did this here.

    To clarify a few things:

    • winget supports Windows 10, version 1809 or later. This means that it's compatible with LTSC 2019 (build 1809) and LTSC 2021 (build 21H2). It isn't compatible with earlier versions of LTSC because of this requirement.
    • If you're more interested in using DISM customize and deploy Windows images, I recommend reading this article from TenForums here. Although this article focuses more on injecting drivers into the install image, you can use the Add-ProvisionedAppxPackage command I detailed in my GitHub Discussions post in place of these commands, and you can use the guide to help you package everything into an ISO for deployment.

    I hope that can help you out! Ultimately, I do think that the documentation could be improved, but I also think that the real issue here is that Windows 10 LTSC doesn't include the App Installer package by default. This would make it much easier to install winget. Just double-click on the msixbundle file, and you're done! This is unlikely, though, so I agree that more documentation on this would be welcome (or, potentially even packaging winget as an executable binary for systems where the Microsoft Store is disabled/uninstalled).

  6. Zamiell commented on Dec 7, 2021

    @Zamiell
    Author

    Thanks, that is good info.

    winget supports Windows 10, version 1809 or later. This means that it's compatible with LTSC 2019 (build 1809) and LTSC 2021 (build 21H2). It isn't compatible with earlier versions of LTSC because of this requirement.

    I put this in the OP.

    If you're more interested in using DISM customize and deploy Windows images

    I did not consider integrating winget into the Windows source itself, but that is smart and I imagine that some people would want to do that.

    After thinking about this a little more, I feel like in the context of "automatically installing extra software on first Windows boot", integrating winget into the source doesn't seem to get you much. I think that you (probably?) can't (or shouldn't) integrate all of the software that you want to install into the source (e.g. for me I need Visual Studio Code, Notepad++, NodeJS, Git). So, since you are going to have a post-installation script anyway, it seems like you might as well install winget at that point to keep the installation source more vanilla.

  7. mariobrostech commented on Dec 7, 2021

    @mariobrostech

    Thanks for the feedback!

    For my use case, my list of packages changes depending on which system I'm installing Windows on. For that reason, while I want winget preinstalled on all of my machines, I don't want the same set of packages shared between them, so I instead opt to use the winget export -o command to get a list of installed packages and then winget import -i to import the list of packages on each machine. For a fully automated deployment, I agree that this wouldn't make sense, but for a setup like mine, this is why I prefer integrating winget directly into the Windows image itself.

  8. Zamiell commented on Dec 8, 2021

    @Zamiell
    Author

    since you are going to have a post-installation script anyway, it seems like you might as well install winget at that point to keep the installation source more vanilla.

    I rescind my previous statement. After another 24 hours of playing with winget in post-installation scripts, I cannot get winget to function in a reliable way. Sometimes, computers must be restarted entirely for winget to start appearing in the path.

    Thus, I have opted to integrate winget into the source using dism, which seems to be a very reliable solution. I'll update the OP accordingly.

  9. mariobrostech commented on Dec 8, 2021

    @mariobrostech

    Awesome, I'm glad you found that helpful!

  10. denelon commented on Dec 8, 2021

    @denelon
    Collaborator

    Similar to Windows Server 2022, the Windows Package Manager should be considered experimental only on Windows 10 LTSC 1809 and 21H2. These would still not be officially supported, but they may be possible with released versions of the Windows Package Manager. We're still working through the dependencies and other long term support implications.

  11. mariobrostech commented on Dec 12, 2021

    @mariobrostech

    Similar to Windows Server 2022, the Windows Package Manager should be considered experimental only on Windows 10 LTSC 1809 and 21H2. These would still not be officially supported, but they may be possible with released versions of the Windows Package Manager. We're still working through the dependencies and other long term support implications.

    This is unfortunate, albeit expected. UWP apps in general aren't very well supported in Windows 10 LTSC versions as-is, let alone updating them. Has your team considered an approach similar to the one that PowerShell 7 has taken where updates can be handled via Microsoft Update, which works on both LTSC 2019 and 2021? This way, you could distribute an installation package for those who wish to install winget on their Windows 10 Server/LTSC systems, and any updates could be handled either manually or via Microsoft Update.

    I know this is probably a pretty sizable undertaking, but if it means having official support for Server/LTSC, it might be something to consider. What are your thoughts?

  12. denelon commented on Dec 13, 2021

    @denelon
    Collaborator

    mariobrostech we're looking at all of our options here. Unfortunately, you are correct regarding UWP apps on Windows 10 LTSC versions. Anything we add to LTSC versions has a very long engineering support tail. We also need to ensure all other teams agree to take on the additional risk and expense of supporting any additions. Taking the Windows Package Manager down to Windows 10 (1809) was already a large undertaking. Supporting LTSC and Server OS SKUs was not approved based on our 1.0 release date. We have been looking at the next release cycles and working with other teams to understand the total impact and cost for becoming supported on those platforms. If this changes, we will certainly share the exciting news.

  13. Shilionz commented on Dec 27, 2021

    @Shilionz

    There may be another way for installing winget package on Windows LTSC.
    My system version is 19044.1415 LTSC.
    Firstly, find the URL of the app installer page on Microsoft Store. This can be done by googling "App Installer Microsoft store". And the URL is https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1.
    Secondly, type the URL into Online link generator for Microsoft store (https://store.rg-adguard.net/). Download all the dependency package for targeted machine platform (e.g. x86, x64).
    Thirdly, install download package using Windows Powershell (using Powershell 7 may suffer some issue). Note that you need to install VCLibs UWPDesktop firstly.
    Add-AppxPackage [package-path]

    Finally you can use winget in command line. Or double clicking msix package to install them directly. This will work even after restarting the system.
    Wish this comment is helpful.

  14. locked and limited conversation to collaborators on Feb 18, 2022
  15. converted this issue into a discussion #1956 on Feb 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-DocsIt's a documentation issue that really should be on MicrosoftDocs

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions