winget-cli
winget-cli copied to clipboard
WinGet on Windows Server Core
I'd like WinGet to function correctly on Windows Server Core. The main gap identified by @jantari was related to the way WinGet determines the locale for package metadata.
Quote from the discussion below:
I looked into it and this API does appear to not be present in Server Core (meaning this error from our call to it is expected). That of course depends on my ability to map from the internal identifier to the marketing name, which should not be considered infallible.
I think at this point we could confidently wrap the implementation of Locale::GetUserPreferredLanguages to prevent the error from escaping. The default state would be that locale was not included in the installer selection if the call failed.
This is a good workaround in the interim.
Originally posted by @JohnMcPMS in https://github.com/microsoft/winget-cli/discussions/2361#discussioncomment-8559871
Some additional context and thoughts for this issue. I will refer to Windows Servers default install, without Desktop Experience, as "Windows Server Core" or "Server Core" for brevity, even though that term is no longer officially correct.
- The goal is to get winget shipped in-box with Windows Server 2025 Core installations, and easier to get going on Windows Server 2022 Core installations. Currently the bootstrapping process is very involved and kind of hacky.
- In my own VM-based testing with Server 2022 Core, this one API call: https://github.com/microsoft/winget-cli/blob/180a8d7d5ad3fe90c3a038f9e5ffda5ae77c289a/src/AppInstallerCLICore/Workflows/ManifestComparator.cpp#L629-L633 failing is the last blocker before the all-important
winget installcommand can run successfully. No further workarounds, shims or shenanigans needed. This means we're already "close to the finish line" on Server Core compatibility. - The above API call does succeed on Windows Server Core 2022 with the AppCompatibility FoD installed
- There seem to be more errors/blockers for getting winget to run on Server 2019 Core. I wasn't able to investigate and solve these, but I'd be totally happy if it worked on 2022 and 2025 Core first. 2019 Core would be nice to have later.
- Winget has already been announced to ship as part of the default Windows Server 2025 with Desktop Experience install. This is great, but the Desktop Experience install is a huge compatibility bandaid you'd only use when absolutely necessary, and many environments therefore mix both Core and Desktop-Experience deployments. The inability to use winget across them all is a blocker to its adoption even if it were partially available OOTB.
- Some ideas for addressing the failing
Locale::GetUserPreferredLanguagesAPI call:- Find and use an alternative API that works on Server Core, or be naughty and get the locale from the registry somewhere as a fallback
- Catch the error and just default to a packages' DefaultLocale when the user's preferred locale cannot be determined (I believe this is what @JohnMcPMS suggested in their own words)
- You said a locale is required to use the "msstore" source so just block/refuse installs from the "msstore" source when the user's preferred locale cannot be determined - just like when the source agreements weren't accepted. I personally, and I imagine many business customers, will exclusively use private package repositories for software deployments to Servers anyway and never the community repo or msstore.
- In addition to the Locale-API blocker discussed above, you also brought up that we also don't have a good way to determine which packages are suitable for an environment with no desktop experience. I firmly believe this is not on winget to solve and doesn't have to be addressed together with the Locale API issue or to ship winget inbox with Windows Server Core. Still, some additional thoughts for when there is time to address this:
- Package compatibility with Windows Server installs currently has to consider Windows Server Core, Windows Server Core with the AppCompatibility FoD and Windows Server with Desktop Experience. If Microsoft ever introduces an "AppCompatibilty FoD 2" as a further in-between choice, the package manifest spec should be able to support that too (keep it flexible/extensible)
- Many community repo package authors will understandably forego testing compatibility with these 3 different deployment scenarios of Windows Server in all its various versions. Many if not most packages will therefore probably never have up-to-date compatibility metadata for Windows Server.
- Automated pipelines could test whether the installation of a package succeeds on all these different Windows Server versions and configurations, but cannot assert the software functioning
- Software being compatible with Server Core is not a simple yes/no checkbox. If software "A" only works partially, or maybe even doesn't open at all but the installer registered COM servers and DLLs which another software "B" depends on and CAN use successfully on Server Core then is software "A" compatible with Core or not?
- winget should therefore never refuse to install any package, marked compatible/incompatible through its metadata or not, on any deployment-type of Windows Server. In the example above, if I want to install software "B" which is marked compatible with Server Core, and it depends on software "A" which technically isn't really compatible with Server Core but installs enough to satisfy the dependencies of software "B" then it would be really infuriating to have winget refuse to install it just because some community manifest author (understandably) didn't consider this usecase.
- It is also possible for an administrator to solve any compatibility issue there might have been preventing a certain software to run on Server Core. This would mean that the software technically wasn't compatible with a fresh vanilla VM install of Server Core, and any automated tests or package authors would therefore rightfully mark it as incompatible in the package metadata, but a crafty Windows Server admin could create application compatibility shims or manually add a missing DLL etc. to make the application work. I know I've had success with this, so again it would be very unproductive to have winget prohibit me from installing a package that I know I can make work.
- winget could print a warning though when installing packages that aren't explicitly marked as compatible with the installed flavor of Windows Server (Core / Core + FoD)
- It's maybe possible to utilize the existing manifest metadata fields Platform and Dependencies.WindowsFeatures for a package to indicate compatibility with Server Core and/or Server Core with the AppCompatibility Feature.
@Karl-WE tagging you because you had some thoughts on this as well. You specifically said:
I would suggest a whitelisting method that comes via new items in manifest like CoreOSCompatibility for Windows Server / Azure Stack HCI, WS DCtr Azure Edition Core Installation mode compatibility and CoreOSFoDCompatibility for Core Installation mode plus requirement of FoD.
Source. Personally, as I've explained above I am against a whitelisting approach and think due to the impossibility of determining a software as "for sure 100% incompatible" with Server Core, winget should at most warn the user and never prohibit package installations.
@jantari was a long read but I agree with you in most parts. Also your reasons with or better said against whitelisting are very reasonable. Thanks for adding your valueable thoughts.
I strongly agree on the mixed environment of core and GUI install options and the adoption rate of winget.
Personally would like to focus on Windows Server 2025 as supported and 2022 as unsupported. 2019 is out of mainstream support and as such no hope, by definition, for any change or backport.
In general, I agree with what was stated. There may be some minor differences in my thinking currently.
Adding "allow" or "deny" lists in WinGet is something I'm currently opposed to. That kind of granularity comes with too much overhead. That's why we created the REST APIs, so enterprise customers could select which packages (and versions) they wanted to support in their own source. Of course, that means we have all kinds of interesting policies in the WinGet community repository, but the client was designed with many of these use cases in mind for future scenarios.
WinGet does have the "--force" argument, which is essentially giving users the ability to tell WinGet: "I don't really care what you think, or what the manifest says, just do what I told you. 😊"
Given that, I think having some kind of metadata in the manifest describing which target OS platform/versions a package has been tested or verified against is goodness. The client would essentially make determinations as it does today with respect to which installer it thinks is most appropriate for the device at the point in time the command is run. If no suitable match is found, WinGet would report the results, but the user could simply force the "install"/"upgrade".
If an existing version of the package is present on the system, there are other implications to consider, but I agree. An administrator should be able to override the default behavior and manage packages how they see fit.
There are several dimensions evaluated when selecting an installer. I don't know if we need to extend the list, but I'm including it below for reference. I think extending "Target Platform" makes the most sense in the context of this discussion. I'm also thinking on Server without desktop experience, the default installation mode should be "silent".
- Architecture (ARM64, x64, x86)
- Installer Type (exe, MSI, MSIX, portable)
- Locale (BCP 47)
- Scope (User vs. Machine)
- Target Platform (Windows.Desktop)
Hi @denelon would using the language value from this registry key be translatable to a locale?
Looking at ProcessMonitor, winget or a library used by it currently already queries PreferredUILanguages inside HKLM\System\CurrentControlSet\Control\MUI\Settings. This contains a BCP 47 language tag on my systems, and this key also exists on Server Core 2022 out of the box.
However I believe the problem with both these keys is that they show the machine locale and winget would probably rather use the current user's locale preference. Quickly searching through the current user's registry with reg query "HKCU" /f "en-US" /d /s on Server Core 2022 shows a few results too though:
HKEY_CURRENT_USER\Control Panel\Desktop\MuiCached
MachinePreferredUILanguages REG_MULTI_SZ en-US
HKEY_CURRENT_USER\Control Panel\International
LocaleName REG_SZ en-US
HKEY_CURRENT_USER\Control Panel\International\User Profile
Languages REG_MULTI_SZ en-US
HKEY_CURRENT_USER\Control Panel\International\User Profile System Backup
Languages REG_MULTI_SZ en-US
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Internet Explorer\International
AcceptLanguage REG_SZ en-US,en;q=0.5
There are probably more approved ways to get to this information too, because the International PowerShell module is pre-installed on Server Core 2022 and works. There's some good cmdlets in there (check Get-Command -Module International -Verb Get). This means we can successfully run cmdlets such as:
- Get-WinSystemLocale
- Get-WinHomeLocation
- Get-WinUserLanguageList
I haven't debugged whether these call Core-compatible APIs or access the registry directly, but I'd expect sixteen layers of enterprisey factory-factories aka APIs so that should be good for winget.
Unrelated, I'll soon have some more details on the Server Core 2022 compatibility of winget. My original observations in February were somewhat flawed because I was working on a system I had already experimented on and tried lots of things prior so it turns out it's not JUST that one API call after all.
Update with additional observations regarding Server Core (2022) compatibility:
I have to make a late follow-up to this post; what I observed above isn't incorrect but I have just deployed a new, untouched Server 2022 Core and made some additional observations. The VM I had used for the troubleshooting above wasn't "clean" because I had already experimented a bunch trying to get winget to run, so here's my new (re-)discoveries:
winget depends on Windows.Globalization.dll. This library isn't present on Server Core 2022, you have to copy this file out of System32 from a machine with the Desktop Experience or with the AppCompatibility FoD installed and put it into your winget program directory next to winget.exe.
Just adding this file has already allowed winget on my new, vanilla Server 2022 Core VM to install some packages, however another package was still failing to install with the dreaded Class not registered error. I don't know exactly what exact code paths were taken here, but some troubleshooing revealed that the issue was caused by winget not understanding that an API it tried to use (Windows.System.UserProfile.GlobalizationPreferences) is actually also provided by the aforementioned Windows.Globalization.dll despite the namespaces not matching up. Winget kept trying to find Windows.System.UserProfile.dll, which I don't think is winget's fault but just default fallback behavior from Windows for DLL discovery.
On my GUI systems there's a registry key (HKLM\SOFTWARE\Microsoft\WindowsRuntime\ActivatableClassId\Windows.System.UserProfile.GlobalizationPreferences) that I believe is responsible for pointing apps to the correct DLL to use for that type (there's a DllPath key there that points to C:\Windows\System32\Windows.Globalization.dll), however I wasn't sure what kind of side-effects it would have to manually create this key on my Server Core system and I wasn't able to get it to appear naturally by running regsvr32.exe Windows.Globalization.dll, so what I ended up doing was creating a symlink in the winget program directory named Windows.System.UserProfile.dll that links to the Windows.Globalization.dll in the same location:
This workaround makes winget find the correct DLL it's looking for under the wrong name without having to edit global registry keys or system directories which could confuse and break other applications.
Now, interestingly, after applying these two fixes I currently do NOT need to set my locale preference using the winget settings.json file on this system to be able to install all the software I want. However I would still recommend performing all three fixes (copying over Windows.Globalization.dll, creating the symlink, setting the locale preference in settings.json) as they're harmless and winget goes through lots of different code paths during installations, calling locale/language APIs many different places and I've seen Class not registered failures related to that at many different stages of the install and show flows by now.
Copy-pasted from the related discussion https://github.com/microsoft/winget-cli/discussions/2361#discussioncomment-10623088
Are there any updates on more official Server Core support?
How about we use enUS as locale until we have proper fix? At least so we can use winget on Core? I think that provides a better experience than not having access to winget at least and provides a sane default.
WinGet is available on Windows Server Core 2025.
You may need to specify a locale or add one to your settings until we get the updated version checked in with a default value.
@denelon I dont find such a package on a Windows Server Core 2025 container (mcr.microsoft.com/windows/servercore:ltsc2025 / 10.0.26100.4349).
Get-WindowsOptionalFeature -Online | Where-Object FeatureName -like '*winget*' returns nothing and trying to enable the feature by the name above fails.
Enable-WindowsOptionalFeature : Feature name WingetSupportOnServerCore is
unknown.
What am I missing? (possibly that this wont work inside a container for different reasons....)
Hello again @denelon - this was closed as completed, but I am not sure anyone has actually got it working? Is this intended for external consumption?
I can't find this optional feature either:
Do let me know if there is something else I can provide to this.
I'm not sure this exists, and can't really understand why it was closed. I guess I'll open a new "bug" issue since there is no response here, and the feature does not exist in a usable fashion, nor apparently documented anywhere.
Same things for Win Server Standard (without user experience)
I have now had a chance to test Server 2025 and I can confirm that the optional feature does not exist for me too. I guess we'll need to open a new issue again.
can confirm Get-WindowsOptionalFeature -Online | ? FeatureName -like *winget* returns nothing on mcr.microsoft.com/windows/servercore:10.0.26100.6899-amd64