无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 22836|回复: 97
打印 上一主题 下一主题

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

  [复制链接]
跳转到指定楼层
1#
发表于 2019-3-24 22:52:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dos时代菜鸟 于 2021-6-18 12:30 编辑

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

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

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

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

bootmode-2021.06.18.7z (1.82 MB, 下载次数: 97)

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




2021新版 pecmd 也有所改进,
改进后 的 如下:2021.01.14
bootmode.2021.2.7z (1.67 MB, 下载次数: 160)






PE下 用pecmd 脚本 bootmode.7z (1.82 MB, 下载次数: 258) 压缩包中包含 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 需要把 ** 变成 --)
--------------
  1. TEAM CALL $ --ret:mode1 Kernel32.dll,GetFirmwareEnvironmentVariableW, "",{00000000-0000-0000-0000-000000000000},0,0 | CALL $ --ret:mode1 Kernel32.dll,GetLastError, ""
  2. IFEX $%mode1% = 1 ,ENVI MODE1=BIOS! find $%mode1%=998 ,ENVI MODE1=UEFI ! ENVI MODE1=Unknow
  3. MESS %mode1%
复制代码
----------------------


exe 方案 用这个 detectefi.7z (22.24 KB, 下载次数: 143) 由 adef 提供,很好用。

如果是 win10 系统 powershell 3.0 的话 可以尝试用这个
bmx.7z (576 Bytes, 下载次数: 84)

如果你的系统 可以运行 bcdedit 列出 bcd 内容,可以用这个
B2.7z (896 Bytes, 下载次数: 104)




点评

我发过帖子,但被两个傻瓜破坏心情,果然又倒退多年。  发表于 2019-3-26 04:49
这帖子所有回复都没抓到关键,依赖BCD都不好  发表于 2019-3-26 04:48

评分

参与人数 1无忧币 +5 收起 理由
chshrm + 5 很给力!

查看全部评分

2#
 楼主| 发表于 2019-3-24 23:34:14 | 只看该作者
通过 {current }可以半段 当前系统 对应的 bcd 选项。
回复

使用道具 举报

3#
发表于 2019-3-24 23:39:50 来自手机 | 只看该作者
bcd判断不了,还得用其它方法,有个第三方命令可以。

点评

如果 存在 path 就可以通过 exe /efi 判断出 至于 pe 可这样:  详情 回复 发表于 2019-3-24 23:55
回复

使用道具 举报

4#
 楼主| 发表于 2019-3-24 23:54:51 | 只看该作者

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

使用道具 举报

5#
 楼主| 发表于 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 可这样:
  1. for /f "tokens=2* delims=  " %%A in ('reg query HKLM\System\CurrentControlSet\Control /v PEFirmwareType') DO SET Firmware=%%B
  2. :: Note: delims is a TAB followed by a space.
  3. if %Firmware%==0x1 echo The PC is booted in BIOS mode.
  4. if %Firmware%==0x2 echo The PC is booted in UEFI mode.
复制代码
回复

使用道具 举报

6#
 楼主| 发表于 2019-3-25 00:02:10 | 只看该作者

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

使用道具 举报

7#
发表于 2019-3-25 08:12:48 来自手机 | 只看该作者
启动模式传递过来了,只能对应efi或者exe去启动,所以bcd里并不需要指明这个,只需要是哪个盘哪个分区或者哪里的哪个镜像文件。
回复

使用道具 举报

8#
 楼主| 发表于 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 加上。重启也会。



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

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

  18. ECHO.
  19. ECHO    BCD启动项列表(!boot_mode!):
  20. for /l %%n in (1,1,!n!) do (
  21.   set "item_type="
  22.   if %%n equ !current_n! ( set "item_type={Current}")
  23.   if %%n equ !bootmgr_n! ( set "item_type={Bootmgr}")
  24.   echo   ---%%n---!item_type!------------
  25.   for %%a in (description,device,systemroot,path) do (
  26.        set "lx=            %%a" & set "lx=!lx:~-12!"
  27.        if defined %%n_%%a  echo   !lx! : "!%%n_%%a!"
  28.   )
  29. )
  30. ECHO ---------------------------
  31. echo.

  32. pause
复制代码
回复

使用道具 举报

9#
发表于 2019-3-25 09:44:20 | 只看该作者
很简单  判断启动文件是否是EFI  当然了  PE下无效

点评

bcd 中记载的 path 项目 是可以删掉的,丝毫不影响系统启动。  详情 回复 发表于 2019-3-25 10:17
回复

使用道具 举报

10#
 楼主| 发表于 2019-3-25 10:17:36 | 只看该作者
2012jiashanni 发表于 2019-3-25 09:44
很简单  判断启动文件是否是EFI  当然了  PE下无效

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

点评

我用的API  详情 回复 发表于 2019-3-25 11:23
回复

使用道具 举报

11#
发表于 2019-3-25 10:23:09 | 只看该作者
一般人的电脑上,你这么判断多半不会错,但是鼓捣引导的人机器上就不行了。

点评

是的,奇葩情况比较难搞  详情 回复 发表于 2019-3-25 10:41
回复

使用道具 举报

12#
 楼主| 发表于 2019-3-25 10:41:53 | 只看该作者
本帖最后由 dos时代菜鸟 于 2019-3-25 10:49 编辑
窄口牛 发表于 2019-3-25 10:23
一般人的电脑上,你这么判断多半不会错,但是鼓捣引导的人机器上就不行了。

是的,奇葩情况比较难搞
看看这个,在探测 bcd 前先删掉 {bootmgr} 中的 path ,如果 bcdedit 能够回填 ,那一定是 efi 的启动模式了。


  1. @echo off
  2. setlocal ENABLEDELAYEDEXPANSION
  3. set /a n=0
  4. set /a current_n=-1
  5. set /a bootmgr_n=-1
  6. bcdedit /deletevalue {bootmgr} path
  7. for /f "tokens=1* delims= " %%a in ('bcdedit /enum ') do (
  8.   set "lx=%%a" &  if /i "!lx:~0,1!"=="-" set /a n+=1
  9.   set "!n!_%%a=%%b"
  10.   if /i "%%b"=="{current}" (set /a current_n=!n!)
  11.   if /i "%%b"=="{bootmgr}" (set /a bootmgr_n=!n!)
  12. )

  13. set "boot_mode=-1"
  14. IF defined !current_n!_path (
  15.   for %%c in (!current_n!) do ( for %%q in (!%%c_path!) do (
  16.       if /i "%%~xq"==".efi" set "boot_mode=UEFI"
  17.       if /i "%%~xq"==".exe" set "boot_mode=Leagcy-Bios"
  18.   ))
  19. )
  20. if !boot_mode! equ -1 (IF defined !bootmgr_n!_path (
  21.   for %%c in (!bootmgr_n!) do ( for %%q in (!%%c_path!) do (
  22.       if /i "%%~xq"==".efi" set "boot_mode=UEFI"
  23.   ))
  24. ))
  25. ECHO.
  26. ECHO    BCD启动项列表(!boot_mode!):
  27. for /l %%n in (1,1,!n!) do (
  28.   set "item_type="
  29.   if %%n equ !current_n! ( set "item_type={Current}")
  30.   if %%n equ !bootmgr_n! ( set "item_type={Bootmgr}")
  31.   echo   ---%%n---!item_type!------------
  32.   for %%a in (description,device,systemroot,path) do (
  33.        set "lx=            %%a" & set "lx=!lx:~-12!"
  34.        if defined %%n_%%a  echo   !lx! : "!%%n_%%a!"
  35.   )
  36. )
  37. ECHO ---------------------------
  38. echo.

  39. pause
复制代码

回复

使用道具 举报

13#
发表于 2019-3-25 10:47:18 来自手机 | 只看该作者
那个第三方可以,我试了,因为我的bcd路径根本就不是常规的位置,它可以正确判断,但是我现在的精简版系统支持不全,它运行不了。

点评

第三方软件 是什么?  详情 回复 发表于 2019-3-25 12:09
要是 bcd 位置变动 bcdedit 能读取出来么? 如果能,可以尝试 用 bcdedit /deletevalue 把 {bootmgr} 的 path 删掉,然后再 bcdedit /enum ,看 {bootmgr} 的 path 是什么,如果能回填出来,path 指向的扩展名是 ef  详情 回复 发表于 2019-3-25 10:53
回复

使用道具 举报

14#
发表于 2019-3-25 10:49:39 来自手机 | 只看该作者
我之前的h77是不允许多硬盘混合引导的,现在的主板是可以的。想怎么启动就怎么启动,想往哪装系统就往哪装。
回复

使用道具 举报

15#
 楼主| 发表于 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 模式 不回填。
回复

使用道具 举报

16#
发表于 2019-3-25 11:23:58 | 只看该作者
dos时代菜鸟 发表于 2019-3-25 10:17
bcd 中记载的 path 项目 是可以删掉的,丝毫不影响系统启动。

我用的API

点评

论坛好像有人问过,也有人用 api 编过程序。还有 au3 的  详情 回复 发表于 2019-3-25 12:11
回复

使用道具 举报

17#
发表于 2019-3-25 11:48:26 来自手机 | 只看该作者
找不到,它找不到bcd的正确位置。

点评

如果 新建一个 bcd ,看是否在 {bootmgr} 里有 path 呢?  详情 回复 发表于 2019-3-25 12:34
那就不好办了  详情 回复 发表于 2019-3-25 11:52
回复

使用道具 举报

18#
 楼主| 发表于 2019-3-25 11:52:29 | 只看该作者
窄口牛 发表于 2019-3-25 11:48
找不到,它找不到bcd的正确位置。

那就不好办了
回复

使用道具 举报

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

第三方软件 是什么?
回复

使用道具 举报

20#
 楼主| 发表于 2019-3-25 12:11:27 | 只看该作者

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

使用道具 举报

21#
发表于 2019-3-25 12:29:05 来自手机 | 只看该作者
就应该就是楼上这位程大师的。

点评

这个我也关注并下载了。  详情 回复 发表于 2019-3-25 12:32
回复

使用道具 举报

22#
 楼主| 发表于 2019-3-25 12:32:48 | 只看该作者
窄口牛 发表于 2019-3-25 12:29
就应该就是楼上这位程大师的。

这个我也关注并下载了。
回复

使用道具 举报

23#
 楼主| 发表于 2019-3-25 12:34:26 | 只看该作者
窄口牛 发表于 2019-3-25 11:48
找不到,它找不到bcd的正确位置。

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

使用道具 举报

24#
发表于 2019-3-25 16:48:42 来自手机 | 只看该作者
默认是有的,要专门删掉才会没有。
回复

使用道具 举报

25#
发表于 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


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

点评

这个文件可以删除的吧?要是被删掉就蛋疼了。  详情 回复 发表于 2019-3-25 21:59
回复

使用道具 举报

26#
发表于 2019-3-25 21:59:02 | 只看该作者
江南一根葱 发表于 2019-3-25 20:59
@echo off

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


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

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

使用道具 举报

27#
 楼主| 发表于 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 变了位置变了名字的就不行了。
回复

使用道具 举报

28#
 楼主| 发表于 2019-3-26 09:29:29 | 只看该作者

好的,看来我要研究下了
回复

使用道具 举报

29#
发表于 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?m ... &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?m ... &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



   

点评

关于Windows是否是UEFI启动, 是否可以简单用命令mountvol z: /s来识别呢? MBR的不能加载EFI分区, 批处理应该怎么写呢, 欢迎讨论  详情 回复 发表于 2021-3-2 09:50
Win7不支持UEFI,不能说我这判断方式不靠谱  发表于 2019-3-26 18:38
方案1貌似有点问题,win7 x64 的 UEFI 启动它判断成 BIOS 启动了。  详情 回复 发表于 2019-3-26 09:45
回复

使用道具 举报

30#
发表于 2019-3-26 09:40:15 | 只看该作者
网上有小工具,https://github.com/xcat2/xcat-co ... cat/netboot/windows

附件管理员运行。

detectefi.rar (23.66 KB, 下载次数: 35)

点评

adef兄, 你提供的detectefi有问题,只适用于64位系统,这个detectefi.exe是64位VC8.0编写的,因此用于32位系统会出错。这里有个问题: 32位系统下面有UEFI启动吗?结果是有的,虽然32位的UEFI固件很少,问题  详情 回复 发表于 2019-4-14 23:23
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2024-11-25 19:07

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表