部署 – 如何阻止Windows 10安装修改BIOS启动设置?
我们正在通过iPXE为PXEboot设置一些系统,并根据主服务器状态,正常启动或通过wimboot和MDT重新映像.系统配置为首先从网络引导. iPXE和wimboot都在UEFI下运行.
它运行良好,除了在Windows安装结束时,BIOS已被修改为指向新的Windows启动管理器作为主启动设备.因此,如果不输入BIOS并更改设置,则无法再次成像. 我理解为什么引导顺序会因为wimboot / MDT进程涉及多次重启而改变.但我真的想要将PXE作为主要引导始终保持或者操作引导顺序,以便在完成后首先使用网络. (我的PXE服务器将传递网络引导机会以允许安装工作或在不需要映像时单独保留系统.) 更新 – 我看到两种可能性: >弄清楚Windows安装程序如何告诉UEFI从目标安装盘启动,并在完成Windows安装以重新启动到PXE启动时执行相同的操作.
了解以下内容:
>在Linux上,这将是相当简单的,通过efibootmgr 一旦我理解了启动顺序和Windows API的UEFI规范,代码(C,为我们正在使用的64位构建)并不是太糟糕.这需要构建到需要管理权限并静态链接Windows运行时的exe中,然后在重新启动之前安装操作系统后在MDT中运行它. 首先,您必须声明有权调用API.使用一个小帮手: 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); } 然后打电话 SetPrivilege(GetCurrentProcess(),SE_SYSTEM_ENVIRONMENT_NAME,TRUE)); 接下来,获取引导选项列表(uint16_t值的串联): 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; } 然后,您可以迭代每个引导选项,为它形成Boot ####变量名称,然后使用它来获取包含该选项信息的结构.您将需要查看第一个活动选项是否具有“描述”等于“Windows启动管理器”. Description是结构中偏移量为6的以null结尾的宽字符串. 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(),bootOptionInfoBuffer,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 } } 现在,如果您找到了活动的WBM和非WBM引导选项,并且第一个WBM选项位于wbmOffset,并且第一个非WBM选项位于nonWBMOffset,则wbmOffset< nonWBMOffset,使用以下内容交换BootOrder变量中的条目: 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,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; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |