WinGet — замечательное средство автоматической установки приложений. Не надо тратить время на скачивание актуальных инсталляторов и забивать себе голову тонкостями ключей тихой установки. Просто запускаешь скрипт с подборкой своих программ и готово!
Но есть нюанс © Установщик пакетов не входит в поставку Windows! Это не вполне очевидно, потому что winget «сразу» работает в начисто установленной ОС. Однако он не включен в WIM-образ, а скачивается уже по окончании установки системы с помощью магазина Windows. И временной интервал загрузки варьируется. Поэтому нельзя просто взять и прицепить скрипт установки приложений к установке Windows.
Сегодня я расскажу, как автоматизировать процесс загрузки и регистрации winget, когда его нет в Windows.
[+] Сегодня в программе
Ручной способ
Детали могут варьироваться в зависимости от издания Windows. Для самого сложного расклада способ изложен в документации Windows IoT: Using WinGet to Install Apps on Windows IoT Enterprise. В этом издании нет магазина, поэтому требуется ручная загрузка всех компонентов.
Метод также подходит для издания LTSC, поскольку оно идентично IoT. Наконец, он должен сработать и в серверных системах, для которых winget в принципе не позиционируется (читатель Alexandr Petnitsky подтверждает успешную работу скрипта в Windows Server 2022).
Автоматический способ (скрипт)
Я просто автоматизировал ручные шаги по загрузке и установке всего необходимого.
Скачайте скрипт winget-install.zip, разблокируйте его, потом выполняйте от имени администратора.
Для работы winget нужен он сам – это установщик пакетов Microsoft.DesktopAppInstaller, а также Microsoft.VCLibs.x64 и Microsoft.UI.Xaml.2.8. Еще понадобится файл лицензии, который можно скачать из любого релиза winget.
Примечание. Microsoft объявила устаревшим способ распространения VCLibs из центра загрузок, поэтому ссылка на пакет может перестать работать.
# doc https://learn.microsoft.com/en-us/windows/iot/iot-enterprise/deployment/install-winget-windows-iot
# blog https://www.outsidethebox.ms/22409
$ErrorActionPreference = 'SilentlyContinue'
$ProgressPreference = 'SilentlyContinue'
$AppInstaller = 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle'
$VCLibs = 'Microsoft.VCLibs.x64.14.00.Desktop.appx' # https://download.microsoft.com/download/4/7/c/47c6134b-d61f-4024-83bd-b9c9ea951c25/Microsoft.VCLibs.x64.14.00.Desktop.appx
$Xaml = 'Microsoft.UI.Xaml.2.8.x64.appx'
$components = @($VCLibs, $Xaml, $AppInstaller)
$license = '5e4a105df01840b0bbf00985e4f57c1e_License1.xml' #from v1.7.10582 assets
Write-Host "Downloading winget and dependencies..."
Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile .\$AppInstaller
Invoke-WebRequest -Uri https://aka.ms/$($VCLibs) -OutFile .\$VCLibs
Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/$($Xaml ) -OutFile .\$Xaml
(Invoke-RestMethod -Uri https://github.com/microsoft/winget-cli/releases/download/v1.7.10582/$($license)).OuterXML | Out-File $license
Write-Host "Installing winget..."
# Deploy provisional package for all users
Add-AppxProvisionedPackage -Online -PackagePath .\$($AppInstaller) -LicensePath .\$($license)
Remove-Item -Path .\$($license) -Force
$components | ForEach-Object {
# Install downloaded packages...
Add-AppxPackage -Path .\$($_) -ErrorAction 0
# ... and delete them
Remove-Item -Path .\$($_) -Force
}
# if anything went wrong, check out errors
if ($ERROR) {$ERROR | Out-File -FilePath $env:temp\winget-install.log -Append}
Ничего принципиально нового здесь нет. Invoke-WebRequest я показывал в блоге неоднократно (раз, два). Invoke-RestMethod вроде не фигурировал раньше, но смысл тот же (просто скачиваемый файл — XML). Установку скачанных пакетов с помощью Add-AppxPackage я тоже разбирал.
После этого уже можно устанавливать приложения с помощью winget. Например, надергав команд с winget.run или winstall, вы получите что-то вроде:
winget install --id=M2Team.NanaZip -e winget install --id=Notepad++.Notepad++ -e winget install --id=Ghisler.TotalCommander -e winget install --id=DominikReichl.KeePass -e
Однако все эти сайты используют в качестве источника только репозиторий winget. У некоторых программ я предпочитаю магазинную версию (репо msstore) из-за ее автоматического обновления.
Поэтому в моем примере смешанная подборка (NanaZip из магазина). Поскольку у магазинных приложений идентификаторы не предназначены для человеческого восприятия, я сделал хэш-таблицу, чтобы видеть названия приложений.
# Software installation
Start-Sleep -Seconds 10 #before installing software
Write-Host "Installing apps with winget..."
[hashtable]$apps = @{
"NanaZip" = "9N8G7TSCL18R"
"Notepad++" = "Notepad++.Notepad++"
"Total Commander" = "Ghisler.TotalCommander"
"KeePass" = "DominikReichl.KeePass"
}
foreach ($key in $apps.keys) {
winget install --id $($apps[$key]) -e --accept-package-agreements --accept-source-agreements
}
Процесс выглядит так.

Выполнение скрипта по окончании установки Windows
Осталась сущая мелочь — прицепить запуск скрипта к установке системы. Как обычно, выбор между FirstLogonCommands в файле ответов и setupcomplete.cmd.
Здесь нужно учитывать, что по умолчанию некоторые пакеты устанавливают приложения в профиль – например, утилиты Sysinternals. Файл setupcomplete.cmd выполняется от имени учетной записи SYSTEM. В ее профиле такие программы и окажутся, что будет бесполезно для вас.
FirstLogonCommands срабатывают уже после входа в систему, поэтому такой проблеме не подвержены.
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<CommandLine>powershell -command "(Get-Volume).DriveLetter | Foreach-Object {if (Test-Path "${PSItem}:\winget-install.ps1") {powershell -ex bypass -file ${PSItem}:\winget-install.ps1}}"</CommandLine>
<Description>Install winget</Description>
<Order>1</Order>
</SynchronousCommand>
</FirstLogonCommands>
Этот способ вызова скрипта я уже неоднократно показывал в блоге. Сам скрипт выступает в роли маркерного файла — находим его в корне установочного диска и запускаем.
Бонус: быстрая установка своего набора программ на чистой системе
Спустя некоторое время я опубликовал в канале Telegram пост о том, как автоматизировать создание списка любимых приложений для их быстрой установки.
Заключение
Будь у нас winget 20 лет назад, форум про автоустановку приложений не имел бы особого смысла. Да, сторонние менеджеры пакетов вроде Chocolatey далеко не вчера родились. Но ценность и популярность winget обусловлена его наличием «из коробки». Ну, почти :) Надеюсь, со временем он полноценно войдет в состав Windows.
Я потихоньку ухожу от исполнения winget в сторону scoop.sh, который можно использовать как напрямую, так и посредством ansible https://docs.ansible.com/ansible/latest/collections/community/windows/win_scoop_module.html
Работает как в клиентских, так и серверных версиях Windows
Если бы Microsoft раньше раздуплилась, вингет и в серверной бы системе поставлялся сейчас. Собственно этот пост как раз про то, как воткнуть его в сервер и лтсц заодно. Просто заголовок не про это.
Проблема-то не в том что он не работает, а в том что он сам и зависимости не входят в поставку. Ну и это мешает конечно интегрироваться с какими-то другими средствами.