dos时代菜鸟 发表于 2019-3-24 22:52:51

求教(已解决,pecmd脚本方案)判断当前系统是否为 uefi

本帖最后由 dos时代菜鸟 于 2021-6-18 12:30 编辑

问题已经解决,
感谢 liuzhaoyzz 、窄口牛 、adef 、liuzhaoyzz 等诸位大侠的热心回复和提供的思路。

我想弄个 cmd 实现这个功能,进而判断 系统启动类型是 uefi 还是 leagy-bios

鉴于 2021新版win10 已经不能使用以往call dll函数 的方式,

针对新版win10 改进了一下,用了另一个 api



    ENVI$# &ret=*4 0   //申请4个窄字符空间,也可以用   ENVI$ &ret=*2 0 //申请2个宽字符空间
    CALL $--qd --bool --ret:&&r Kernel32.dll,GetFirmwareType,*&ret
    FIND $%&&r%=,
    {*
      //为空,可以认为没有返回数据,当前环境不支持此API,低于Win8版本的系统
      //MESS. 不支持此API。
                CALL $ --ret:r Kernel32.dll,GetFirmwareEnvironmentVariableW,"",{00000000-0000-0000-0000-000000000000},0,0
                CALL $ --ret:mode1 Kernel32.dll,GetLastError, ""
                IFEX $%mode1% = 1 ,envi BootMODE=BIOS! find $%mode1%=998 ,envi BootMODE=UEFI ! envi BootMODE=???1
    }!
    {*
      IFEX #%&&r%=0,MESS API Error.!
      {*
            ENVI?int &ret=&ret1
            IFEX #%&ret1%=0,envi BootMODE=???0。
            IFEX #%&ret1%=1,envi BootMODE=BIOS
            IFEX #%&ret1%=2,envi BootMODE=UEFI
            IFEX #%&ret1%=3,envi BootMODE=???9
      }
    }
mess %Bootmode%




2021新版 pecmd 也有所改进,
改进后 的 如下:2021.01.14







PE下 用pecmd 脚本 压缩包中包含 pecmd x86 /x64 所以在 本地 windows下也可以用。
有的PE 因为 pecmd 版本不同 有的 call 指令略有不同,需要 自行对 bm.ini 进行修改。压缩包中的 pecmd 是 2018新版

脚本解决方案 是 调用 pecmd 加载 kernel32.dll 的 api 句柄
按照网上流行的做法 ,本质就是 通过 给 GetFirmwareEnvironmentVariableW 函数一个 错误的信息,其返回值必为0 ,但是其 错误代码返回值就不一样了。如果错误代码返回 1 说明是 bios ,代表 当前系统不支持 该函数运行,如果 错误代码返回值为 998 ,说明 该句柄运行了,但是运行错误。
值得一提的是,必须 将 kernel32.dll 的GetFirmwareEnvironmentVariableW和 getLastError 两个函数 紧连着使用,以便能够获取 真正的错误返回码。
所以 考虑 用 team 命令将两个 call 链接起来。
pecmd 脚本内容如下:
(根据自身 pecmd 版本 需要将下面源码中 红色部分修改比如 2017版 pecmd 需要把 ** 变成 --)
--------------
TEAM CALL $ --ret:mode1 Kernel32.dll,GetFirmwareEnvironmentVariableW, "",{00000000-0000-0000-0000-000000000000},0,0 | CALL $ --ret:mode1 Kernel32.dll,GetLastError, ""
IFEX $%mode1% = 1 ,ENVI MODE1=BIOS! find $%mode1%=998 ,ENVI MODE1=UEFI ! ENVI MODE1=Unknow
MESS %mode1%----------------------


exe 方案 用这个由 adef 提供,很好用。

如果是 win10 系统 powershell 3.0 的话 可以尝试用这个


如果你的系统 可以运行 bcdedit 列出 bcd 内容,可以用这个





dos时代菜鸟 发表于 2019-3-24 23:34:14

通过 {current }可以半段 当前系统 对应的 bcd 选项。

窄口牛 发表于 2019-3-24 23:39:50

bcd判断不了,还得用其它方法,有个第三方命令可以。

dos时代菜鸟 发表于 2019-3-24 23:54:51

frg521 发表于 2019-3-24 23:32
...

如果删除了 path ,bootmgr 如何知道用什么文件引导进入 windows ,这个技术我还没接触过。一定是 还修改了其他地方 以 与之对应。还请赐教。

dos时代菜鸟 发表于 2019-3-24 23:55:55

本帖最后由 dos时代菜鸟 于 2019-3-24 23:59 编辑

窄口牛 发表于 2019-3-24 23:39
bcd判断不了,还得用其它方法,有个第三方命令可以。

第三方命令 是 用api dll 编的 那个 吧。或者用au3



如果 存在 path 就可以通过 exe /efi 判断出
至于 pe 可这样:
for /f "tokens=2* delims=" %%A in ('reg query HKLM\System\CurrentControlSet\Control /v PEFirmwareType') DO SET Firmware=%%B
:: Note: delims is a TAB followed by a space.
if %Firmware%==0x1 echo The PC is booted in BIOS mode.
if %Firmware%==0x2 echo The PC is booted in UEFI mode.

dos时代菜鸟 发表于 2019-3-25 00:02:10

frg521 发表于 2019-3-24 23:58
...

那可能就是 bootmgr通过自己的 类型 加载 winload 的 类型了吧。这个就 有些难办了。

窄口牛 发表于 2019-3-25 08:12:48

启动模式传递过来了,只能对应efi或者exe去启动,所以bcd里并不需要指明这个,只需要是哪个盘哪个分区或者哪里的哪个镜像文件。

dos时代菜鸟 发表于 2019-3-25 09:36:16

本帖最后由 dos时代菜鸟 于 2019-3-25 10:20 编辑

刚才测试了下 win10 的 bcd没有 path 的情况

leagy uefi模式下 启动项不指定 "path = ....winload.exe"都可以启动

值得一提的是 uefi 模式下 会在 {bootmgr} 项目中增加一个 path 并指定 bootmgrfw.efi 作为启动 bcd 的引导器,即便把 {bootmgr} 中的这个 path 删掉,系统也会在启动的时候 加上,运行 "bcdedit/enum “也会自动加上.
不知道是否是个例,还是普遍现象,如果普遍如此,就可以据此判断系统是否为 uefi 模式启动了。

也就是如果 {bootmgr} 项中 有定义 path 且其指向一个 .efi 文件,就说明是 uefi 启动。否则就是 leagy-bios 模式启动。???
似乎也不妥,如果用 bcdedit /deletevalue 的方式删除 {bootmgr} 中的 path ,系统就不会 回填 path 值了。
而且 leagy-bios 模式 下,bcd 中{bootmgr} 的path 没啥用,如果 leagy-bios中 {bootmgr}的path值乱写,也会影响判断。






如下图,{bootmgr} 项目中 path 已经删除,运行 bcdedit 还是会 自动把 path 加上。重启也会。



@echo off
setlocal ENABLEDELAYEDEXPANSION
set /a n=0
set /a current_n=-1
set /a bootmgr_n=-1
for /f "tokens=1* delims= " %%a in ('bcdedit /enum ') do (
set "lx=%%a" &if /i "!lx:~0,1!"=="-" set /a n+=1
set "!n!_%%a=%%b"
if /i "%%b"=="{current}" (set /a current_n=!n!)
if /i "%%b"=="{bootmgr}" (set /a bootmgr_n=!n!)
)

set "boot_mode=Legacy-BIOS"
IF defined !bootmgr_n!_path (
for %%c in (!bootmgr_n!) do ( for %%q in (!%%c_path!) do (
      if /i "%%~xq"==".efi" set "boot_mode=UEFI"
))
)

ECHO.
ECHO    BCD启动项列表(!boot_mode!):
for /l %%n in (1,1,!n!) do (
set "item_type="
if %%n equ !current_n! ( set "item_type={Current}")
if %%n equ !bootmgr_n! ( set "item_type={Bootmgr}")
echo   ---%%n---!item_type!------------
for %%a in (description,device,systemroot,path) do (
       set "lx=            %%a" & set "lx=!lx:~-12!"
       if defined %%n_%%aecho   !lx! : "!%%n_%%a!"
)
)
ECHO ---------------------------
echo.

pause

2012jiashanni 发表于 2019-3-25 09:44:20

很简单判断启动文件是否是EFI当然了PE下无效

dos时代菜鸟 发表于 2019-3-25 10:17:36

2012jiashanni 发表于 2019-3-25 09:44
很简单判断启动文件是否是EFI当然了PE下无效

bcd 中记载的 path 项目 是可以删掉的,丝毫不影响系统启动。

窄口牛 发表于 2019-3-25 10:23:09

一般人的电脑上,你这么判断多半不会错,但是鼓捣引导的人机器上就不行了。

dos时代菜鸟 发表于 2019-3-25 10:41:53

本帖最后由 dos时代菜鸟 于 2019-3-25 10:49 编辑

窄口牛 发表于 2019-3-25 10:23
一般人的电脑上,你这么判断多半不会错,但是鼓捣引导的人机器上就不行了。
是的,奇葩情况比较难搞
看看这个,在探测 bcd 前先删掉 {bootmgr} 中的 path ,如果 bcdedit 能够回填 ,那一定是 efi 的启动模式了。


@echo off
setlocal ENABLEDELAYEDEXPANSION
set /a n=0
set /a current_n=-1
set /a bootmgr_n=-1
bcdedit /deletevalue {bootmgr} path
for /f "tokens=1* delims= " %%a in ('bcdedit /enum ') do (
set "lx=%%a" &if /i "!lx:~0,1!"=="-" set /a n+=1
set "!n!_%%a=%%b"
if /i "%%b"=="{current}" (set /a current_n=!n!)
if /i "%%b"=="{bootmgr}" (set /a bootmgr_n=!n!)
)

set "boot_mode=-1"
IF defined !current_n!_path (
for %%c in (!current_n!) do ( for %%q in (!%%c_path!) do (
      if /i "%%~xq"==".efi" set "boot_mode=UEFI"
      if /i "%%~xq"==".exe" set "boot_mode=Leagcy-Bios"
))
)
if !boot_mode! equ -1 (IF defined !bootmgr_n!_path (
for %%c in (!bootmgr_n!) do ( for %%q in (!%%c_path!) do (
      if /i "%%~xq"==".efi" set "boot_mode=UEFI"
))
))
ECHO.
ECHO    BCD启动项列表(!boot_mode!):
for /l %%n in (1,1,!n!) do (
set "item_type="
if %%n equ !current_n! ( set "item_type={Current}")
if %%n equ !bootmgr_n! ( set "item_type={Bootmgr}")
echo   ---%%n---!item_type!------------
for %%a in (description,device,systemroot,path) do (
       set "lx=            %%a" & set "lx=!lx:~-12!"
       if defined %%n_%%aecho   !lx! : "!%%n_%%a!"
)
)
ECHO ---------------------------
echo.

pause

窄口牛 发表于 2019-3-25 10:47:18

那个第三方可以,我试了,因为我的bcd路径根本就不是常规的位置,它可以正确判断,但是我现在的精简版系统支持不全,它运行不了。

窄口牛 发表于 2019-3-25 10:49:39

我之前的h77是不允许多硬盘混合引导的,现在的主板是可以的。想怎么启动就怎么启动,想往哪装系统就往哪装。

dos时代菜鸟 发表于 2019-3-25 10:53:47

窄口牛 发表于 2019-3-25 10:47
那个第三方可以,我试了,因为我的bcd路径根本就不是常规的位置,它可以正确判断,但是我现在的精简版系统 ...

要是 bcd 位置变动 bcdedit 能读取出来么?
如果能,可以尝试 用 bcdedit /deletevalue 把 {bootmgr} 的 path 删掉,然后再 bcdedit /enum ,看 {bootmgr} 的 path 是什么,如果能回填出来,path 指向的扩展名是 efi 那肯定是 uefi 启动的。

我刚弄了个 cmd 好像可以了,{bootmgr}的内容,开始我是 用 /set 修改 path ,结果不回填,但是要是 path 被干掉了,bcdedit 就会 给再填一个。这个在 leagcy-bios 模式 不回填。

2012jiashanni 发表于 2019-3-25 11:23:58

dos时代菜鸟 发表于 2019-3-25 10:17
bcd 中记载的 path 项目 是可以删掉的,丝毫不影响系统启动。

我用的API

窄口牛 发表于 2019-3-25 11:48:26

找不到,它找不到bcd的正确位置。

dos时代菜鸟 发表于 2019-3-25 11:52:29

窄口牛 发表于 2019-3-25 11:48
找不到,它找不到bcd的正确位置。

那就不好办了

dos时代菜鸟 发表于 2019-3-25 12:09:29

窄口牛 发表于 2019-3-25 10:47
那个第三方可以,我试了,因为我的bcd路径根本就不是常规的位置,它可以正确判断,但是我现在的精简版系统 ...

第三方软件 是什么?

dos时代菜鸟 发表于 2019-3-25 12:11:27

2012jiashanni 发表于 2019-3-25 11:23
我用的API

论坛好像有人问过,也有人用 api 编过程序。还有 au3 的

窄口牛 发表于 2019-3-25 12:29:05

就应该就是楼上这位程大师的。

dos时代菜鸟 发表于 2019-3-25 12:32:48

窄口牛 发表于 2019-3-25 12:29
就应该就是楼上这位程大师的。

这个我也关注并下载了。

dos时代菜鸟 发表于 2019-3-25 12:34:26

窄口牛 发表于 2019-3-25 11:48
找不到,它找不到bcd的正确位置。

如果 新建一个 bcd ,看是否在{bootmgr} 里有 path 呢?

窄口牛 发表于 2019-3-25 16:48:42

默认是有的,要专门删掉才会没有。

江南一根葱 发表于 2019-3-25 20:59:22

本帖最后由 江南一根葱 于 2019-3-25 21:01 编辑

@echo off

:: 获取管理员权限运行批处理
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if '%errorlevel%' NEQ '0' (
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs" 1>nul 2>nul
exit /b
:gotAdmin
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" ) 1>nul 2>nul

find "Detected boot environment: BIOS" C:\Windows\Panther\setupact.log >nul
if errorlevel 1 echo 当前系统工作在UEFI环境 &&pause
if errorlevel 0 echo 当前系统工作在BIOS环境 &&pause

exit


注意区别大小写
不过貌似这个是安装时的启动日志,当前启动应该也可以用这种类似的办法吧

527104427 发表于 2019-3-25 21:59:02

江南一根葱 发表于 2019-3-25 20:59
@echo off

:: 获取管理员权限运行批处理


这个文件可以删除的吧?要是被删掉就蛋疼了。

我记得有些清理垃圾的批处理,会把.log清掉的哦。

dos时代菜鸟 发表于 2019-3-26 08:25:21

本帖最后由 dos时代菜鸟 于 2019-3-26 08:26 编辑

我是发现 bcdedit 会在 uefi 启动模式下 自动给 bcd 的 {bootmgr} 添加 path 值,而在 legacy-bios 模式 就不会,所以,我的思路是将 {bootmgr} 的path 内容保存后删掉,再用 bcdedit /v 看有没有 这个 path 来判断 是什么模式启动的,然后在把 之前保存的 path 恢复回 {bootmgr} 。

只要 bcdedit 能够 正常读取当前 bcd 就可以。但对于那些 bcd 变了位置变了名字的就不行了。

dos时代菜鸟 发表于 2019-3-26 09:29:29

frg521 发表于 2019-3-25 21:49
...

好的,看来我要研究下了

liuzhaoyzz 发表于 2019-3-26 09:37:00

本帖最后由 liuzhaoyzz 于 2019-3-27 11:10 编辑

   
1、基于BCDEDIT的方案是不可靠的。一些情况下bcdedit根本就运行不了。
2、基于setupact.log判断的方案是不可靠的,不同系统根本就没有这个文件。
3、检查 HKLM\System\CurrentControlSet\Control\PEFirmwareType 注册表值来查看电脑是启动到 UEFI 模式还是 BIOS 模式,需要运行 wpeutil UpdateBootInfo 来确保该值存在。----这个方案也不靠谱!
4、基于bootice判断的方案是可靠的,pauly大神用的也是windows API,问题是没有命令行的调用方法。
所以,解决方案:
1、2010hook兄给出的方案,这个可以直接批处理调用,不用第三方:(UEFI-WIN7不准确)
@echo off
rem 原理参见2010hook发表在http://bbs.wuyou.net/forum.php?mod=redirect&goto=findpost&ptid=409010&pid=3718253&fromuid=298214
:DetectUEFI
for /f %%a in ('reg query "HKLM\HARDWARE\UEFI\ESRT" /s 2^>nul^|find /i "{"') do set "IsEFI=%%a"
if "!IsEFI:~-1!" equ "}" (
set "loader=efi"
echo UEFI启动
) else (
set "loader=exe"
echo BIOS启动
)
pause
2、windows api调用,里面有源代码和原理。
判断当前系统是BIOS启动还是UEFI启动,是Windows还是PE,内存和磁盘空间情况(by双... - RAMOS - 无忧启动论坛 - Powered by Discuz! http://bbs.wuyou.net/forum.php?mod=viewthread&tid=412368&extra=page%3D1

3、批处理搭配adef推荐的detectefi小程序。
@echo off
pushd %~dp0
reg add "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v "DisableUNCCheck" /t "REG_DWORD" /d "1" /f 1>nul 2>nul
rem cd /d "%~dp0"
detectefi |find /i "UEFI" && call :UEFI|| call :BIOS
echo 继续下一句
popd %~dp0
pause
exit /b
pause

:BIOS
echo BIOS启动
pause
exit /b

:UEFI
echo UEFI启动
pause
exit /b
pause


   

adef 发表于 2019-3-26 09:40:15

网上有小工具,https://github.com/xcat2/xcat-core/tree/master/xCAT-server/share/xcat/netboot/windows

附件管理员运行。

页: [1] 2 3
查看完整版本: 求教(已解决,pecmd脚本方案)判断当前系统是否为 uefi