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.
# 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' $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.
Dmitry Pugachev
Я потихоньку ухожу от исполнения winget в сторону scoop.sh, который можно использовать как напрямую, так и посредством ansible https://docs.ansible.com/ansible/latest/collections/community/windows/win_scoop_module.html
Работает как в клиентских, так и серверных версиях Windows
Vadim Sterkin
Если бы Microsoft раньше раздуплилась, вингет и в серверной бы системе поставлялся сейчас. Собственно этот пост как раз про то, как воткнуть его в сервер и лтсц заодно. Просто заголовок не про это.
Проблема-то не в том что он не работает, а в том что он сам и зависимости не входят в поставку. Ну и это мешает конечно интегрироваться с какими-то другими средствами.