Вопрос или проблема
У меня есть ПК с BIOS (не UEFI) с двумя SSD: Windows 10 и Ubuntu. GRUB и Linux находятся на первом SSD, и GRUB загружает ту же ОС, которая была загружена последней. На машине включен Wake-on-LAN, и иногда я получаю к ней удаленный доступ (SSH, RDP, VNC и т. д.).
Если последняя загруженная ОС была Ubuntu, и я хочу запустить Windows, я могу сделать это удаленно: разбудить машину; подключиться по SSH к Ubuntu; отредактировать /etc/default/grub, установить Windows как по умолчанию (вместо сохраненной ОС); выполнить update-grub; перезагрузить. При следующей загрузке GRUB будет Windows.
Но если последней используемой ОС является Windows, GRUB продолжит загружать Windows.
Есть ли способ REMOTELY получить доступ к Windows и настроить компьютер на смену следующей загрузки на Linux снова? Как только загрузится Linux, я смогу по SSH подключиться к нему и изменить параметры GRUB по мере необходимости.
Если был бы только один SSD, возможно, я мог бы использовать утилиты Windows FDISK и bootrec, чтобы отметить раздел Linux (пока он был основным разделом) как загрузочный и воссоздать загрузочную запись, перезаписав GRUB. Этот вариант не жизнеспособен с двумя дисками.
Мне интересно, если создать маленький загрузочный раздел Linux на первом SSD, чтобы я мог использовать Fdisk Windows для включения этого раздела как загрузочного и запускать Linux напрямую, но, опять же, мне нужно будет перезаписывать загрузочный сектор (заменяя GRUB) каждый раз, когда я захочу переключить ОС по умолчанию с Windows на Linux. Из Linux мне нужно будет снова установить GRUB и установить Windows как по умолчанию.
Я мог бы использовать TFTP-сервер, где GRUB получит свою конфигурацию. У меня на сети есть Raspberry Pi, работающий круглосуточно, который мог бы выступать в качестве TFTP-сервера.
Итак, коротко: есть ли решение, которое полностью работает на удаленно доступной машине, для REMOTELY изменения следующей загрузки GRUB с Windows на Linux?
Это решение добавляет маленький (1 МБ) раздел, содержащий FAT-форматированный том, на второй диск, где установлен Windows. Новый пункт меню добавляется в GRUB, который при выборе загрузит Windows, если файл windows
находится в папке .boot
на этом FAT-форматированном томе. Если файл windows
не существует, при выборе нового пункта меню GRUB загрузит Ubuntu.
Обратите внимание, что Windows установлена в первом основном разделе на втором диске. Вместо использования отдельных томов System, Windows и Recovery, хранящихся в отдельных разделах, как описано на сайте Microsoft BIOS/MBR-based hard drive partitions, используется один том, который содержит содержимое трех отдельных томов.
Используемые операционные системы:
Windows 10 22H2 (19045.4780)
Ubuntu 24.04 LTS
Ниже приведены шаги для реализации этого решения.
-
Создать и инициализировать новый раздел. Здесь предполагается, что второй диск использует таблицу разделов MBR, где раздел, содержащий Windows, является первым и единственным элементом в таблице. Я ввел следующее в окне командной строки администратора.
diskpart list disk select disk 1 list partition select partition 1 shrink desired=1 create partition primary size=1 format fs=fat quick label=grubfat assign letter=u exit mkdir u:\.boot attrib +h u:\.boot copy nul u:\.boot\windows
Ниже приведен вывод. Имя нового тома –
GRUBFAT
, а новая буква диска –U:
. У папки.boot
установлен скрытый атрибут.C:\windows\system32>diskpart Microsoft DiskPart version 10.0.19041.3636 Copyright (C) Microsoft Corporation. На компьютере: DESKTOP-F3VMONS DISKPART> list disk Диск ### Статус Размер Свободно Динамический Gpt -------- ------------- ------- ------- --- --- Диск 0 В сети 100 ГБ 0 Б * Диск 1 В сети 150 ГБ 0 Б DISKPART> select disk 1 Диск 1 теперь выбранный диск. DISKPART> list partition Раздел ### Тип Размер Смещение ------------- ---------------- ------- ------- Раздел 1 Основной 149 ГБ 1024 КБ DISKPART> select partition 1 Раздел 1 теперь выбранный раздел. DISKPART> shrink desired=1 DiskPart успешно уменьшил объем на: 1024 КБ DISKPART> create partition primary size=1 DiskPart успешно создал указанный раздел. DISKPART> format fs=fat quick label=grubfat 100 процентов завершено. DiskPart успешно отформатировал объем. DISKPART> assign letter=u DiskPart успешно назначил букву диска или точку монтирования. DISKPART> exit Выход из DiskPart... C:\Windows\System32>mkdir u:\.boot C:\Windows\System32>attrib +h u:\.boot C:\windows\system32>copy nul u:\.boot\windows 1 файл(ов) скопирован. C:\windows\system32>
-
Создать утилиту
setboot
для Windows и Ubuntu. Эта утилита имеет следующие допустимые записи.Команда Действие setboot
Показывает либо Windows
, либоUbuntu
как текущую ОС по умолчанию для загрузки.setboot windows
Устанавливает Windows как ОС по умолчанию для загрузки. setboot ubuntu
Устанавливает Ubuntu как ОС по умолчанию для загрузки. Версия для Windows показана ниже. Этот скрипт следует поместить в файл с именем
setboot.cmd
.@echo off setlocal enableextensions set theFile=u:\.boot\windows set p1=%1 if not defined p1 ( if exist %theFile% ( echo Windows ) else ( echo Ubuntu ) exit /b 0 ) set p1=%p1:"=% set p2=%2 if not defined p2 ( if /i "%p1%" == "windows" ( if not exist %theFile% type nul >%theFile% exit /b 0 ) if /i "%p1%" == "ubuntu" ( if exist %theFile% del %theFile% exit /b 0 ) ) echo usage: setboot [windows ^| ubuntu] exit /b 1
Версия для Ubuntu показана ниже. Этот скрипт следует поместить в файл с именем
setboot
.#!/usr/bin/bash theFile=/media/grubfat/.boot/windows if [[ $# -eq 0 ]]; then if [[ -e $theFile ]]; then echo Windows else echo Ubuntu fi exit 0 fi if [[ $# -eq 1 ]]; then if [[ ${1,,} == windows ]]; then if [[ ! -e $theFile ]]; then cat /dev/null >$theFile; fi exit 0 fi if [[ ${1,,} == ubuntu ]]; then if [[ -e $theFile ]]; then rm $theFile; fi exit 0 fi fi echo "usage: setboot [windows | ubuntu]" exit 1
Чтобы этот скрипт работал правильно, необходимо добавить следующую строку в файл
/etc/fstab
.LABEL=GRUBFAT /media/grubfat vfat gid=100,dmask=007,fmask=007,utf8 0 0
-
Добавить новый пункт меню в GRUB. Ниже приведен шаблон для
menuentry
, который нужно добавить в файл/etc/grub.d/40_custom
.Обратите внимание: Вы можете пропустить команды
echo
иsleep
, если хотите.menuentry 'Ubuntu или Windows 10' --class os $menuentry_id_option 'Ubuntu-or-Windows' { insmod part_msdos if [ -e (hd1,msdos2)/.boot/windows ]; then echo 'Загрузка Windows 10' sleep 2 # # Ниже должен быть копия содержимого пункта меню для Windows. # else echo 'Загрузка Ubuntu' sleep 2 # # Ниже должен быть копия содержимого пункта меню для Ubuntu. # fi }
Содержимое
menuentry
для Windows и Ubuntu можно скопировать из файла/boot/grub/grub.cfg
. В качестве справки, пункт меню ‘Ubuntu или Windows 10’, который я добавил в свой файл/etc/grub.d/40_custom
, приведен ниже. Примечание: У меня установлен Ubuntu на BIOS, загружающемся с первого диска, который использует таблицу разделов GUID (GPT).menuentry 'Ubuntu или Windows 10' --class os $menuentry_id_option 'Ubuntu-or-Windows' { insmod part_msdos if [ -e (hd1,msdos2)/.boot/windows ]; then echo 'Загрузка Windows 10' sleep 2 # # Ниже должен быть копия содержимого пункта меню для Windows. # savedefault insmod part_msdos insmod ntfs set root="hd1,msdos1" if [ x$feature_platform_search_hint = xy ]; then search --no-floppy --fs-uuid --set=root --hint-bios=hd1,msdos1 --hint-efi=hd1,msdos1 --hint-baremetal=ahci1,msdos1 A436DDD636DDA996 else search --no-floppy --fs-uuid --set=root A436DDD636DDA996 fi parttool ${root} hidden- # drivemap -s (hd0) ${root} chainloader +1 else echo 'Загрузка Ubuntu' sleep 2 # # Ниже должен быть копия содержимого пункта меню для Ubuntu. # recordfail savedefault load_video gfxmode $linux_gfx_mode insmod gzio if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi insmod part_gpt insmod ext2 set root="hd0,gpt2" if [ x$feature_platform_search_hint = xy ]; then search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 c171bdaf-cef0-4b42-adbf-04118f6c9917 else search --no-floppy --fs-uuid --set=root c171bdaf-cef0-4b42-adbf-04118f6c9917 fi linux /boot/vmlinuz-6.8.0-41-generic root=UUID=c171bdaf-cef0-4b42-adbf-04118f6c9917 ro quiet splash $vt_handoff initrd /boot/initrd.img-6.8.0-41-generic fi }
Ниже изображение нового меню GRUB.
Оставьте комментарий, если у вас есть вопросы. Новые пользователи также могут попробовать задать новый вопрос с ссылкой на этот ответ.
Ответ или решение
Чтобы удаленно изменить опцию загрузки GRUB с Windows на Linux без прямого доступа к BIOS, вы можете использовать решение, описанное ниже. Оно предполагает создание маленького (1 МиБ) раздела, содержащего FAT-форматированный объем на втором диске с Windows. Этот раздел будет содержать файл, который позволит вам управлять, какая операционная система будет загружена при следующем старте.
Шаги по реализации решения
-
Создание и инициализация нового раздела:
- Предполагается, что на втором диске используется таблица разделов MBR, где раздел с Windows является первым и единственным в таблице. Введите следующие команды в окне командной строки с правами администратора:
diskpart list disk select disk 1 list partition select partition 1 shrink desired=1 create partition primary size=1 format fs=fat quick label=grubfat assign letter=u exit mkdir u:\.boot attrib +h u:\.boot copy nul u:\.boot\windows
- Это создаст новый том с меткой
GRUBFAT
и буквой дискаU:
. Папка.boot
будет скрыта.
- Предполагается, что на втором диске используется таблица разделов MBR, где раздел с Windows является первым и единственным в таблице. Введите следующие команды в окне командной строки с правами администратора:
-
Создание утилиты
setboot
:-
Разработайте скрипт для Windows, который будет управлять выбором операционной системы. Скопируйте следующий код в файл с именем
setboot.cmd
:@echo off setlocal enableextensions set theFile=u:\.boot\windows set p1=%1 if not defined p1 ( if exist %theFile% ( echo Windows ) else ( echo Ubuntu ) exit /b 0 ) set p1=%p1:"=% set p2=%2 if not defined p2 ( if /i "%p1%" == "windows" ( if not exist %theFile% type nul >%theFile% exit /b 0 ) if /i "%p1%" == "ubuntu" ( if exist %theFile% del %theFile% exit /b 0 ) ) echo usage: setboot [windows ^| ubuntu] exit /b 1
-
Аналогично создайте скрипт для Ubuntu, сохраните его как
setboot
:#!/usr/bin/bash theFile=/media/grubfat/.boot/windows if [[ $# -eq 0 ]]; then if [[ -e $theFile ]]; then echo Windows else echo Ubuntu fi exit 0 fi if [[ $# -eq 1 ]]; then if [[ ${1,,} == windows ]]; then if [[ ! -e $theFile ]]; then cat /dev/null >$theFile; fi exit 0 fi if [[ ${1,,} == ubuntu ]]; then if [[ -e $theFile ]]; then rm $theFile; fi exit 0 fi fi echo "usage: setboot [windows | ubuntu]" exit 1
-
Для правильной работы скрипта добавьте строку в
/etc/fstab
:LABEL=GRUBFAT /media/grubfat vfat gid=100,dmask=007,fmask=007,utf8 0 0
-
-
Добавление новой записи в меню GRUB:
- Добавьте новую запись в файл
/etc/grub.d/40_custom
с содержимым:menuentry 'Ubuntu или Windows 10' --class os $menuentry_id_option 'Ubuntu-or-Windows' { insmod part_msdos if [ -e (hd1,msdos2)/.boot/windows ]; then echo 'Загрузка Windows 10' sleep 2 # Здесь вставьте содержимое меню для загрузки Windows else echo 'Загрузка Ubuntu' sleep 2 # Здесь вставьте содержимое меню для загрузки Ubuntu fi }
- Добавьте новую запись в файл
Примечание:
После добавления этих настроек вы сможете управлять загрузкой операционных систем удаленно. Для этого вам нужно будет подключиться к Windows, запустить скрипт setboot
для установки следующей загрузки Linux.
Теперь, когда вы хотите загрузить Ubuntu, выполните на удаленном доступе команду setboot ubuntu
. Для загрузки Windows выполните setboot windows
, как описано выше.
Таким образом, вы получите возможность удаленно переключать приоритет загрузки GRUB между Windows и Ubuntu, используя только утилиты и команды, доступные на самом ПК. Если у вас возникнут вопросы, не стесняйтесь задавать их!