Skip to content

Instantly share code, notes, and snippets.

@likamrat
Created February 13, 2023 00:41
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save likamrat/cae833a6e5b3461709f14c093c21c293 to your computer and use it in GitHub Desktop.
Save likamrat/cae833a6e5b3461709f14c093c21c293 to your computer and use it in GitHub Desktop.
Installing Winget om Windows Server 2019/2022
Write-Information "This script needs be run on Windows Server 2019 or 2022"
If ($PSVersionTable.PSVersion.Major -ge 7){ Write-Error "This script needs be run by version of PowerShell prior to 7.0" }
# Define environment variables
$downloadDir = "C:\WinGet"
$gitRepo = "microsoft/winget-cli"
$msiFilenamePattern = "*.msixbundle"
$licenseFilenamePattern = "*.xml"
$releasesUri = "https://api.github.com/repos/$gitRepo/releases/latest"
# Preparing working directory
New-Item -Path $downloadDir -ItemType Directory
Push-Location $downloadDir
# Downloaing artifacts
function Install-Package {
param (
[string]$PackageFamilyName
)
Write-Host "Querying latest $PackageFamilyName version and its dependencies..."
$response = Invoke-WebRequest `
-Uri "https://store.rg-adguard.net/api/GetFiles" `
-Method "POST" `
-ContentType "application/x-www-form-urlencoded" `
-Body "type=PackageFamilyName&url=$PackageFamilyName&ring=RP&lang=en-US" -UseBasicParsing
Write-Host "Parsing response..."
$regex = '<td><a href=\"([^\"]*)\"[^\>]*\>([^\<]*)<\/a>'
$packages = (Select-String $regex -InputObject $response -AllMatches).Matches.Groups
$result = $true
for ($i = $packages.Count - 1; $i -ge 0; $i -= 3) {
$url = $packages[$i - 1].Value;
$name = $packages[$i].Value;
$extCheck = @(".appx", ".appxbundle", ".msix", ".msixbundle") | % { $x = $false } { $x = $x -or $name.EndsWith($_) } { $x }
$archCheck = @("x64", "neutral") | % { $x = $false } { $x = $x -or $name.Contains("_$($_)_") } { $x }
if ($extCheck -and $archCheck) {
# Skip if package already exists on system
$currentPackageFamilyName = (Select-String "^[^_]+" -InputObject $name).Matches.Value
$installedVersion = (Get-AppxPackage "$currentPackageFamilyName*").Version
$latestVersion = (Select-String "_(\d+\.\d+.\d+.\d+)_" -InputObject $name).Matches.Value
if ($installedVersion -and ($installedVersion -ge $latestVersion)) {
Write-Host "${currentPackageFamilyName} is already installed, skipping..." -ForegroundColor "Yellow"
continue
}
try {
Write-Host "Downloading package: $name"
$tempPath = "$(Get-Location)\$name"
Invoke-WebRequest -Uri $url -Method Get -OutFile $tempPath
Add-AppxPackage -Path $tempPath
Write-Host "Successfully installed:" $name
} catch {
$result = $false
}
}
}
return $result
}
Write-Host "`n"
function Install-Package-With-Retry {
param (
[string]$PackageFamilyName,
[int]$RetryCount
)
for ($t = 0; $t -le $RetryCount; $t++) {
Write-Host "Attempt $($t + 1) out of $RetryCount..." -ForegroundColor "Cyan"
if (Install-Package $PackageFamilyName) {
return $true
}
}
return $false
}
$licenseDownloadUri = ((Invoke-RestMethod -Method GET -Uri $releasesUri).assets | Where-Object name -like $licenseFilenamePattern ).browser_download_url
$licenseFilename = ((Invoke-RestMethod -Method GET -Uri $releasesUri).assets | Where-Object name -like $licenseFilenamePattern ).name
$licenseJoinPath = Join-Path -Path $downloadDir -ChildPath $licenseFilename
Invoke-WebRequest -Uri $licenseDownloadUri -OutFile ( New-Item -Path $licenseJoinPath -Force )
$result = @("Microsoft.DesktopAppInstaller_8wekyb3d8bbwe") | ForEach-Object { $x = $true } { $x = $x -and (Install-Package-With-Retry $_ 3) } { $x }
$msiFilename = ((Get-ChildItem -Path $downloadDir) | Where-Object name -like $msiFilenamePattern ).name
$msiJoinPath = Join-Path -Path $downloadDir -ChildPath $msiFilename
# Installing winget
Add-ProvisionedAppPackage -Online -PackagePath $msiJoinPath -LicensePath $licenseJoinPath -Verbose
Write-Host "`n"
# Test if winget has been successfully installed
if ($result -and (Test-Path -Path "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe")) {
Write-Host "Congratulations! Windows Package Manager (winget) $(winget --version) installed successfully" -ForegroundColor "Green"
} else {
Write-Host "Oops... Failed to install Windows Package Manager (winget)" -ForegroundColor "Red"
}
# Cleanup
Push-Location $HOME
Remove-Item $downloadDir -Recurse -Force
@ikhansa812
Copy link

@cheema-corellian
Copy link

This script did not work for me.

Attempt 1 out of 3...
Querying latest Microsoft.DesktopAppInstaller_8wekyb3d8bbwe version and its dependencies...
Parsing response...
Microsoft.VCLibs.140.00 is already installed, skipping...
Microsoft.VCLibs.140.00 is already installed, skipping...
Microsoft.VCLibs.140.00.UWPDesktop is already installed, skipping...
Microsoft.VCLibs.140.00.UWPDesktop is already installed, skipping...
Microsoft.UI.Xaml.2.7 is already installed, skipping...
Microsoft.DesktopAppInstaller is already installed, skipping...
Microsoft.DesktopAppInstaller is already installed, skipping...
Microsoft.DesktopAppInstaller is already installed, skipping...
Add-ProvisionedAppPackage : PackagePath must point to a package, not a directory
At C:\users\cheema\WinGet_WinSrv.ps1:94 char:1
+ Add-ProvisionedAppPackage -Online -PackagePath $msiJoinPath -LicenseP ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Add-AppxProvisionedPackage], PSArgumentException
    + FullyQualifiedErrorId : Add-AppxProvisionedPackage,Microsoft.Dism.Commands.AddAppxProvisionedPackageCommand



Program 'winget.exe' failed to run: No applicable app licenses foundAt C:\users\cheema\WinGet_WinSrv.ps1:100 char:69
+ ... ulations! Windows Package Manager (winget) $(winget --version) instal ...
+                                                  ~~~~~~~~~~~~~~~~.
At C:\users\cheema\WinGet_WinSrv.ps1:100 char:69
+ ... ulations! Windows Package Manager (winget) $(winget --version) instal ...
+                                                  ~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [], ApplicationFailedException
    + FullyQualifiedErrorId : NativeCommandFailed

Congratulations! Windows Package Manager (winget)  installed successfully


PS C:\Users\cheema> winget
Program 'winget.exe' failed to run: No applicable app licenses foundAt line:1 char:1
+ winget
+ ~~~~~~.
At line:1 char:1
+ winget
+ ~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [], ApplicationFailedException
    + FullyQualifiedErrorId : NativeCommandFailed

@garzamSEA
Copy link

Add-ProvisionedAppPackage : PackagePath must point to a package, not a directory
At C:\users\cheema\WinGet_WinSrv.ps1:94 char:1

  • Add-ProvisionedAppPackage -Online -PackagePath $msiJoinPath -LicenseP ...
  •   + CategoryInfo          : InvalidArgument: (:) [Add-AppxProvisionedPackage], PSArgumentException
      + FullyQualifiedErrorId : Add-AppxProvisionedPackage,Microsoft.Dism.Commands.AddAppxProvisionedPackageCommand
    

Hello @ikhansa812 and @cheema-corellian . I am getting the exact same error (minus the C:\Users directory). I've tried running with and without admin privs. However, I still get the error message "Add-ProvisionedAppPackage : PackagePath must point to a package, not a directory". Should I manually create the C:\WinGet directory? It seems that the script is not creating the $downloadDir and/or not downloading the packages from the repo. It is completely possible that I am misunderstanding what the script is trying to do though.

Thank you for providing this script. Looking forward to getting WinGet on my server :-)

@clayrosenthal
Copy link

Is there a modified version of this to make this work with sysprep?

@DaveidWeba
Copy link

DaveidWeba commented Jul 19, 2023

@garzamSEA If you are still struggling, this is the easiest way to get WinGet installed on Server 2019 or 2022:

# Install Chocolately Package Manager
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
$env:Path = [System.Environment]::ExpandEnvironmentVariables([System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User"))

# Install WinGet from Chocolatey
choco install winget
choco install winget.powershell

# Fix Permissions
TAKEOWN /F "C:\Program Files\WindowsApps" /R /A /D Y
ICACLS "C:\Program Files\WindowsApps" /grant Administrators:F /T

# Add Environment Path
$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
if ($ResolveWingetPath) {
	$WingetPath = $ResolveWingetPath[-1].Path
}
$ENV:PATH += ";$WingetPath"
$SystemEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)
$SystemEnvPath += ";$WingetPath;"
setx /M PATH "$SystemEnvPath"

If you prefer to do it manually without the assistance of Chocolatey:

# Create WinGet Folder
New-Item -Path C:\WinGet -ItemType directory -ErrorAction SilentlyContinue

# Install VCLibs
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile "C:\WinGet\Microsoft.VCLibs.x64.14.00.Desktop.appx"
Add-AppxPackage "C:\WinGet\Microsoft.VCLibs.x64.14.00.Desktop.appx"

# Install Microsoft.UI.Xaml from NuGet
Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile "C:\WinGet\Microsoft.UI.Xaml.2.7.3.zip"
Expand-Archive "C:\WinGet\Microsoft.UI.Xaml.2.7.3.zip" -DestinationPath "C:\WinGet\Microsoft.UI.Xaml.2.7.3"
Add-AppxPackage "C:\WinGet\Microsoft.UI.Xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx"

# Install latest WinGet from GitHub
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -OutFile "C:\WinGet\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
Add-AppxPackage "C:\WinGet\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"

# Fix Permissions
TAKEOWN /F "C:\Program Files\WindowsApps" /R /A /D Y
ICACLS "C:\Program Files\WindowsApps" /grant Administrators:F /T

# Add Environment Path
$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
if ($ResolveWingetPath) {
	$WingetPath = $ResolveWingetPath[-1].Path
}
$ENV:PATH += ";$WingetPath"
$SystemEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)
$SystemEnvPath += ";$WingetPath;"
setx /M PATH "$SystemEnvPath"

With either method, you should have a working installation of WinGet on your server. Good luck!
image

@TheBigBear
Copy link

BTW @asheroto has a repo with a working installer working on Windows 10, Windows 11, Server 2022 along with a nice bit.ly alias
https://github.com/asheroto/winget-installer
https://bit.ly/winget-installer

@tristanbarcelon
Copy link

tristanbarcelon commented Jul 24, 2023

@DaveidWeba , I followed the script you provided without using chocolatey but it doesn't seem to work even though it installed properly.

image

Executing winget gives me this nondescript error, as if winget doesn't have permission to execute.

image

It has a newer version of winget based on FileVersion data.

image

Suspecting this to be a permission issue, I reran and added to path. It works now.

TAKEOWN /F "C:\Program Files\WindowsApps" /R /A /D Y
ICACLS "C:\Program Files\WindowsApps" /grant Administrators:F /T

@vrichv
Copy link

vrichv commented Jul 25, 2023

thanks,it works.

@Karl-WE
Copy link

Karl-WE commented Sep 24, 2023

can confirm https://github.com/asheroto/winget-install is so far the best solution available. Rock solid.
thank you @TheBigBear
cc @likamrat

@asheroto
Copy link

asheroto commented Sep 25, 2023

I installed Windows 10, Windows 11, and Server 2022 on Virtual Machines, then ran the install over and over again for several hours one morning and concluded that the newer versions of the prerequisites do not function on Windows 10 and Server 2022. On those OS's, they seem to like version 14.00 of VCLibs and version 2.7.3 of UI.Xaml. I'm not sure if there's a fix for that or if it's truly just a compatibility issue. This is just what I found in testing.

In summary, the store.rg-adguard.net method will probably not work on Windows 10 or Server 2022 because it gets a version of the prerequisites that are too new for those OS's. That method will likely only work on Windows 11+. I could not get Server 2019 to work at all but if someone finds an older prerequisite version that works then maybe we can update the scripts.

This area details the functionality that seems to work:
https://github.com/asheroto/winget-install#script-functionality

@o0101
Copy link

o0101 commented Jan 8, 2024

Thanks @DaveidWeba your comment (no Choco version) is working! I use it here

@autb
Copy link

autb commented Mar 5, 2024

Thanks @DaveidWeba. In one OS (Microsoft Windows Server 2019 Standard), I used the version with chocolatey and also the scripts linked to TAKEOWN and ICACLS, but when running winget command an error came indicating that VCRUNTIME140.DLL and MSVCP140.DLL were not found. Then I downloaded and installed the both x86 and x64 versions of the libs vc_redis : x86 && x64 and all running well now.

@Karl-WE
Copy link

Karl-WE commented Mar 7, 2024

The easiest thing is currently to use the "predeploy" package of Microsoft Terminal which comes with similar prereqs installing these and then continueing with winget msix.

@cheema-corellian
Copy link

The easiest thing is currently to use the "predeploy" package of Microsoft Terminal which comes with similar prereqs installing these and then continueing with winget msix.

@Karl-WE I don't mean to sound ungrateful, but why not provide a link to the said "predeploy" package? And yes, I did Google. And did find various different pieces of software that could be considered relevant. None were called "predeploy" package for MS Terminal.

@aweedman
Copy link

aweedman commented Mar 9, 2024

Hi had winget working for a while on Server 2019. I installed the different packages manually. At some point recently winget stopped working. I tried the non-Chocately script above. It seemed to run currently. Getting when I run winget:

Program 'winget.exe' failed to run: The file cannot be accessed by the systemAt line:1 char:1

  • winget upgrade --all

At line:1 char:1

  • winget upgrade --all
  •   + CategoryInfo          : ResourceUnavailable: (:) [], ApplicationFailedException
      + FullyQualifiedErrorId : NativeCommandFailed
    
    

@Karl-WE
Copy link

Karl-WE commented Mar 12, 2024

@cheema-corellian understand your point. No worries.

Head to Microsoft Terminal releases >Release Version
https://github.com/microsoft/terminal/releases

Use the files from the preinstall kit they contain files also required for winget.

These can be installed on Windows Server 2019/2022 (unsupported), Windows Server 2025 has winget inbox.

Example
Microsoft.WindowsTerminal_1.19.10302.0_8wekyb3d8bbwe.msixbundle_Windows10_PreinstallKit.zip

One can argue that by today some prerequisites are available for download via public webpage, offered by Microsoft like vc redist msix packages.

The hardest part is certainly to get the the package manager running that's a requirement for winget and MSIX.

@pariswells
Copy link

@garzamSEA If you are still struggling, this is the easiest way to get WinGet installed on Server 2019 or 2022:

# Install Chocolately Package Manager
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
$env:Path = [System.Environment]::ExpandEnvironmentVariables([System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User"))

# Install WinGet from Chocolatey
choco install winget
choco install winget.powershell

# Fix Permissions
TAKEOWN /F "C:\Program Files\WindowsApps" /R /A /D Y
ICACLS "C:\Program Files\WindowsApps" /grant Administrators:F /T

# Add Environment Path
$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
if ($ResolveWingetPath) {
	$WingetPath = $ResolveWingetPath[-1].Path
}
$ENV:PATH += ";$WingetPath"
$SystemEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)
$SystemEnvPath += ";$WingetPath;"
setx /M PATH "$SystemEnvPath"

If you prefer to do it manually without the assistance of Chocolatey:

# Create WinGet Folder
New-Item -Path C:\WinGet -ItemType directory -ErrorAction SilentlyContinue

# Install VCLibs
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile "C:\WinGet\Microsoft.VCLibs.x64.14.00.Desktop.appx"
Add-AppxPackage "C:\WinGet\Microsoft.VCLibs.x64.14.00.Desktop.appx"

# Install Microsoft.UI.Xaml from NuGet
Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.7.3 -OutFile "C:\WinGet\Microsoft.UI.Xaml.2.7.3.zip"
Expand-Archive "C:\WinGet\Microsoft.UI.Xaml.2.7.3.zip" -DestinationPath "C:\WinGet\Microsoft.UI.Xaml.2.7.3"
Add-AppxPackage "C:\WinGet\Microsoft.UI.Xaml.2.7.3\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.7.appx"

# Install latest WinGet from GitHub
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/latest/download/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -OutFile "C:\WinGet\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
Add-AppxPackage "C:\WinGet\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"

# Fix Permissions
TAKEOWN /F "C:\Program Files\WindowsApps" /R /A /D Y
ICACLS "C:\Program Files\WindowsApps" /grant Administrators:F /T

# Add Environment Path
$ResolveWingetPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
if ($ResolveWingetPath) {
	$WingetPath = $ResolveWingetPath[-1].Path
}
$ENV:PATH += ";$WingetPath"
$SystemEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)
$SystemEnvPath += ";$WingetPath;"
setx /M PATH "$SystemEnvPath"

With either method, you should have a working installation of WinGet on your server. Good luck! image

You need to use the latest version of .UI.Xaml for this to work now

Install Microsoft.UI.Xaml from NuGet

Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.UI.Xaml/2.8.6 -OutFile "C:\WinGet\Microsoft.UI.Xaml.2.8.6.zip"
Expand-Archive "C:\WinGet\Microsoft.UI.Xaml.2.8.6.zip" -DestinationPath "C:\WinGet\Microsoft.UI.Xaml.2.8.6"
Add-AppxPackage "C:\WinGet\Microsoft.UI.Xaml.2.8.6\tools\AppX\x64\Release\Microsoft.UI.Xaml.2.8.appx"

@pariswells
Copy link

The Invoke-WebRequest looks like its triggering Cloudflares Bot Captcha now for me so I had to use @garzamSEA method

document.createElement('script');cpo.src =
'/cdn-cgi/challenge-platform/h/b/orchestrate/chl_page/v1?ray=87303dcae82cdfab';window._cf_chl_opt.cOgUHash =
location.hash === '' && location.href.indexOf('#') !== -1 ? '#' : location.hash;window._cf_chl_opt.cOgUQuery =
location.search === '' && location.href.slice(0, location.href.length -
window._cf_chl_opt.cOgUHash.length).indexOf('?') !== -1 ? '?' : location.search;if (window.history &&

@Karl-WE
Copy link

Karl-WE commented Apr 16, 2024

you might want to use start-bitstransfer instead of invoke-webrequest for better performance.
i am currently working on a "side quest" to enable a customer with Windows Server 2022 and winget and so far the best automation experience for this unsupported scenario is undoubtly this project:

https://github.com/asheroto/winget-install

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment