我尝试使用wmic
命令来检查 Windows 产品密钥。我检查了一下,看看它是否返回 Windows 产品密钥或空行。但是条件IF "%%Z" == ""
以及IF [%%Z] EQU []
结果总是在执行Echo Lose
,即key不是一个空字符串。
以下示例是显示第一部分的更简单版本。
@ECHO OFF
set cmd=wmic path softwarelicensingservice get OA3xOriginalProductKey
for /f "tokens=1 skip=1" %%Z in ('%cmd% ^| findstr /r /v "^$"') do (set RESULT=%%Z)
IF "%%Z" == "" (Echo Key %RESULT%) Else (Echo Lose)
PAUSE
分配给循环变量(如Z
)的字符串值不能在循环外部引用。条件IF "%%Z" == ""
始终将固定字符串"%Z"
与固定字符串进行比较,""
当然,固定字符串永远不会相等。条件IF [%%Z] EQU []
首先导致尝试将固定字符串[%Z]
转换为 32 位有符号整数值,该值在第一个字符[
时已经失败,因此接下来要对[%Z]
进行字符串比较[]
也永远不会相等。
使用以下代码之前需要了解的一些事实:
- SoftwareLicensingService 类仅在 Windows Vista 或更新的 Windows 客户端版本以及 Windows Server 2008 和更新的 Windows 服务器版本上可用。此类在 Windows Vista 和 Windows Server 2008.
Windows 7 和 Windows Server 2008 R2 上的 SoftwareLicensingService 类没有OA3xOriginalProductKey
属性OA3xOriginalProductKey
。 - Microsoft文档中没有太多关于
OA3xOriginalProductKey
的文章。有 Windows 10 版本 1703 基本级别 Windows 诊断事件和字段Microsoft文档页面,以及 Windows 安装程序或就地升级完成后 OSD 任务序列不会继续,以及部署 Windows 10 企业版许可证,其中包含有关OA3xOriginalProductKey
的一些信息。看起来此属性是在用于 Windows 8、Windows 8.1 和 Windows 10 客户端版本的 OEM 激活 3.0 系统中引入的。
可以使用以下批处理代码:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "RESULT="
for /F "delims=" %%I in ('%SystemRoot%System32wbemwmic.exe PATH SoftwareLicensingService GET OA3xOriginalProductKey /VALUE 2^>nul') do for /F "tokens=1* delims==" %%J in ("%%I") do set "RESULT=%%K"
if not defined RESULT echo Lose& goto EndBatch
echo Key %RESULT%
rem Other commands making use of environment variable RESULT.
:EndBatch
endlocal
pause
在WMIC没有为属性OA3xOriginalProductKey
输出值的情况下,使用 FINDSTR 过滤掉空行没有真正的帮助,因为使用 UTF-16 编码的WMIC的 Unicode 输出带有字节顺序标记 (BOM) 的小端序被在后台启动的cmd.exe
实例处理错误,选项/C
和指定的命令行作为将输出重定向到FINDSTR的附加参数转换为每个字符编码一个字节。
在这种情况下,环境变量RESULT
定义为将单个回车符作为分配给环境变量的字符串。
处理WMIC的 Unicode 输出时cmd.exe
的这种怪癖的解决方法是使用选项/VALUE
在一行上获取属性OA3xOriginalProductKey
的名称及其值,一行之间有一个等号,数据行上方和下方的两个空行。
所有五个捕获的行都由FOR处理,通常完全忽略空行。但是FOR没有空行要处理,因为cmd.exe
将 UTF-16 编码的回车 + 换行 (0D 00 0A 00
) 解释为回车 + 回车 + 换行 (0D 0D 0A
) 的错误导致四个空行被解释为具有单个回车符的行,而开头带有OA3xOriginalProductKey=
的行作为行在末尾也有一个额外的回车符。
因此,每条末尾带有回车符的整行首先分配给循环变量I
。
另一个FOR循环用于处理分配给循环变量的字符串I
这会导致在处理之前从字符串值中删除错误的回车符。
因此,对于四个空行,第二个FOR没有要处理的字符串,因此确实忽略了四个空行。
第二个FOR循环通过使用等号作为字符串分隔符,将包含文本数据的唯一行拆分为两个子字符串。第一个子字符串OA3xOriginalProductKey
分配给循环变量J
,等号之后的第二个子字符串是分配给下一个的键,但一个循环K
如果有键,否则K
没有定义,接下来执行的命令 SET%%K
替换为空字符串。
批处理文件使用前两行完全定义了所需的执行环境,并确保环境变量RESULT
恰好没有使用第三个命令行在批处理文件外部定义。
带有两个FOR和SET命令的长命令行之后的IF条件首先检查环境变量RESULT
现在是否使用实际键(而不仅仅是回车)定义,以确定接下来要执行的ECHO命令。
长命令行也可以是:
for /F "delims=" %%I in ('%SystemRoot%System32wbemwmic.exe PATH SoftwareLicensingService GET KeyManagementServiceMachine /VALUE 2^>nul') do for /F "tokens=2 delims==" %%J in ("%%I") do set "RESULT=%%J"
在这种情况下,只有OA3xOriginalProductKey=
后面的字符串分配给指定的循环变量,J
WMIC是否有密钥输出。否则,秒FOR没有任何东西可以分配给J
,因此命令SET根本不执行,导致环境变量列表中仍然不存在RESULT
。
要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,然后完整而仔细地阅读每个命令的显示帮助页面。
echo /?
endlocal /?
for /?
goto /?
if /?
pause /?
rem /?
set /?
setlocal /?
wmic /?
wmic path /?
wmic path softwarelicensingservice /?
wmic path softwarelicensingservice get /?
阅读有关使用命令重定向运算符的Microsoft文档,了解2>nul
和|
的说明。重定向运算符>
和|
必须使用 FOR 命令行上的插入符号^
进行转义,以便在 Windows 命令解释器在执行命令FOR之前处理此命令行时将其解释为文字字符,该命令使用在后台启动的单独命令进程执行嵌入式命令行。