3 votos

Cómo hago para dejar de Windows 10 Instalar desde la modificación de la BIOS la configuración de arranque?

Estamos configurando algunos sistemas de PXEboot a través de iPXE y, dependiendo de un servidor maestro de estado, ya sea de arranque normalmente o reimagen a través de wimboot y MDT. Los sistemas están configurados para arrancar desde la red de primera. iPXE y wimboot se ejecutan bajo UEFI.

Funciona muy bien, excepto al final de la instalación de windows, la BIOS ha sido modificado para que apunte al nuevo Administrador de Arranque de Windows como el dispositivo de arranque primario. Lo que no puede ser fotografiado de nuevo sin entrar en la bios y cambiar la configuración.

Entiendo por qué la orden de inicio se cambia como el wimboot/MDT proceso implica varios reinicios. Pero realmente me gustaría mantener PXE como arranque primario en todo o manipular el orden de arranque de nuevo a la red de primera. (Mi servidor PXE va a pasar en el arranque de red de oportunidad para permitir la instalación o dejar que el sistema solo cuando la imagen no es necesaria).

Actualización - veo dos posibilidades:

  1. Averiguar cómo el instalador de windows dice UEFI para que arranque desde el destino el disco de instalación, y hacer la misma cosa cuando la instalación de windows se hace para volver a establecer el arranque PXE.
  2. Jugar con el Administrador de Arranque de Windows y BCDEdit después de la instalación de windows a cabo el arranque PXE opción de arrancar desde un disco local (pregunta encontrado en superusuario es básicamente la misma pregunta como aquí. El resultado final discutido allí no es lo que realmente quiero (PXE primero en la configuración de UEFI), pero podría producir el mismo comportamiento (arranque PXE siempre conseguir una oportunidad de actuar antes de que windows se inicia).

2voto

aggieNick02 Puntos 61

Aprendido lo siguiente:

  1. En Linux, esta sería bastante sencillo, a través de efibootmgr
  2. EasyUEFI me deja hacer lo que quiero demasiado - soporte de línea de comandos requiere un bastante barato licencia; pero no me siento una gran función en un nicho de la herramienta gustan, especialmente si hay otras opciones.
  3. bcdedit en una UEFI máquina modifica la configuración de UEFI. Creo que funcionaría.
  4. La especificación UEFI por orden de arranque no es demasiado complicado. El API es realmente sólo GetVariable/SetVariable con variables denominadas BootOrder (obtener/configurar la lista de opciones de arranque en el orden en el que van a ser juzgados) y de Arranque#### (para obtener/establecer información acerca de cada opción de arranque).
  5. No tengo idea de cómo me gustaría escribir una aplicación de windows en contra de la UEFI de la API de windows (¿alguien?)
  6. Windows proporciona una API que, entre otras cosas, envolturas UEFI del GetVariable/SetVariable.

Una vez que entendí la especificación UEFI para el orden de inicio y la API de windows, el código de C++, construido para el de 64 bits ya que es todo lo que estamos usando) no era demasiado malo. Este debe ser construido en un archivo exe que requiere privilegios administrativos y estáticamente enlaces el tiempo de ejecución de windows y, a continuación, ejecuta en MDT después de que se instala el sistema operativo antes de reiniciar.

En primer lugar, usted tiene que reclamar un privilegio de llamar a la API. El uso de una pequeña ayuda:

struct CloseHandleHelper
{
    void operator()(void *p) const
    {
        CloseHandle(p);
    }
};

BOOL SetPrivilege(HANDLE process, LPCWSTR name, BOOL on)
{
    HANDLE token;
    if (!OpenProcessToken(process, TOKEN_ADJUST_PRIVILEGES, &token))
        return FALSE;
    std::unique_ptr<void, CloseHandleHelper> tokenLifetime(token);
    TOKEN_PRIVILEGES tp;
    tp.PrivilegeCount = 1;
    if (!LookupPrivilegeValueW(NULL, name, &tp.Privileges[0].Luid))
        return FALSE;
    tp.Privileges[0].Attributes = on ? SE_PRIVILEGE_ENABLED : 0;
    return AdjustTokenPrivileges(token, FALSE, &tp, sizeof(tp), NULL, NULL);
}

luego de la llamada

SetPrivilege(GetCurrentProcess(), SE_SYSTEM_ENVIRONMENT_NAME, TRUE));

La próxima, obtener la lista de opciones de arranque (una concatenación de uint16_t valores):

const int BUFFER_SIZE = 4096;
BYTE bootOrderBuffer[BUFFER_SIZE];
DWORD bootOrderLength = 0;
const TCHAR bootOrderName[] = TEXT("BootOrder");
const TCHAR globalGuid[] = TEXT("{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}");
DWORD bootOrderAttributes;
bootOrderLength = GetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, BUFFER_SIZE, &bootOrderAttributes);
if (bootOrderLength == 0)
{
    std::cout << "Failed getting BootOrder with error " << GetLastError() << std::endl;
    return 1;
}

A continuación, se puede iterar sobre cada opción de arranque, la forma de la Bota#### nombre de la variable para él, y, a continuación, utilizar para obtener una estructura con información acerca de la opción. Usted querrá ver si la primera opción tiene la "Descripción" igual a "Administrador de Arranque de Windows". Descripción es un terminada en null amplia cadena de caracteres en el desplazamiento 6 en la estructura.

for (DWORD i = 0; i < bootOrderLength; i += 2)
{
    std::wstringstream bootOptionNameBuilder;
    bootOptionNameBuilder << "Boot" << std::uppercase << std::setfill(L'0') << std::setw(4) << std::hex << *reinterpret_cast<uint16_t*>(bootOrderBuffer + i);
    std::wstring bootOptionName(bootOptionNameBuilder.str());
    BYTE bootOptionInfoBuffer[BUFFER_SIZE];
    DWORD bootOptionInfoLength = GetFirmwareEnvironmentVariableEx(bootOptionName.c_str(), globalGuid, bootOptionInfoBuffer, BUFFER_SIZE, nullptr);
    if (bootOptionInfoLength == 0)
    {
        std::cout << "Failed getting option info for option at offset " << i << std::endl;
        return 1;
    }
    uint32_t* bootOptionInfoAttributes = reinterpret_cast<uint32_t*>(bootOptionInfoBuffer);
    //First 4 bytes make a uint32_t comprised of flags. 0x1 means the boot option is active (not disabled)
    if (((*bootOptionInfoAttributes) & 0x1) != 0)
    {
        std::wstring description(reinterpret_cast<wchar_t*>(bootOptionInfoBuffer + sizeof(uint32_t) + sizeof(uint16_t)));
        bool isWBM = boost::algorithm::to_upper_copy<std::wstring>(description) == L"WINDOWS BOOT MANAGER";
        // details - keep track of the value of i for the first WBM and non-WBM options you find, and the fact that you found them
    }
}

Ahora bien, si usted encuentra activo WBM y no WBM las opciones de arranque y la primera WBM opción es wbmOffset, y el primer no-WBM opción es nonWBMOffset, con wbmOffset < nonWBMOffset, cambiar las entradas en el BootOrder variable con el siguiente:

    uint16_t *wbmBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + wbmOffset);
    uint16_t *nonWBMBootOrderEntry = reinterpret_cast<uint16_t*>(bootOrderBuffer + nonWBMOffset);
    std::swap(*wbmBootOrderEntry, *nonWBMBootOrderEntry);
    if (SetFirmwareEnvironmentVariableEx(bootOrderName, globalGuid, bootOrderBuffer, bootOrderLength, bootOrderAttributes))
    {
        std::cout << "Swapped WBM boot entry at offset " << wbmOffset << " with non-WBM boot entry at offset " << nonWBMOffset << std::endl;
    }
    else
    {
        std::cout << "Failed to swap WBM boot entry with non-WBM boot entry, error " << GetLastError() << std::endl;
        return 1;
    }

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: