Удаленно изменить опцию загрузки ОС GRUB с Windows на Linux

Вопрос или проблема

У меня есть ПК с 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

Ниже приведены шаги для реализации этого решения.

  1. Создать и инициализировать новый раздел. Здесь предполагается, что второй диск использует таблицу разделов 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>
    
  2. Создать утилиту 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
    
  3. Добавить новый пункт меню в 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

Оставьте комментарий, если у вас есть вопросы. Новые пользователи также могут попробовать задать новый вопрос с ссылкой на этот ответ.

Ответ или решение

Чтобы удаленно изменить опцию загрузки GRUB с Windows на Linux без прямого доступа к BIOS, вы можете использовать решение, описанное ниже. Оно предполагает создание маленького (1 МиБ) раздела, содержащего FAT-форматированный объем на втором диске с Windows. Этот раздел будет содержать файл, который позволит вам управлять, какая операционная система будет загружена при следующем старте.

Шаги по реализации решения

  1. Создание и инициализация нового раздела:

    • Предполагается, что на втором диске используется таблица разделов 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 будет скрыта.
  2. Создание утилиты 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
  3. Добавление новой записи в меню 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, используя только утилиты и команды, доступные на самом ПК. Если у вас возникнут вопросы, не стесняйтесь задавать их!

Оцените материал
Добавить комментарий

Капча загружается...