%SystemRoot%\System32\systeminfo.exe
的操作系统语言相关输出以ASCII/ANSI/OEM编码方式字符编码,即每个字符使用一个字节,代码页与在命令提示符窗口中运行时显示的代码页相同。代码页取决于用于运行批处理文件的帐户配置的国家(地区)。只要感兴趣的数据不包含代码值大于127的字符(非ASCII字符),代码页实际上并不重要。
systeminfo
通过findstr
过滤的输出是二进制的,文件左侧为十六进制偏移量,冒号后为字节的十六进制值,分号后为它们的ASCII表示。
0000h: 48 6F 73 74 20 4E 61 6D 65 3A 20 20 20 20 20 20 ; Host Name:
0010h: 20 20 20 20 20 20 20 20 20 20 20 50 47 56 2D 50 ; PGV-P
0020h: 46 31 36 35 48 4E 4E 0D 0A 4F 53 20 4E 61 6D 65 ; F165HNN..OS Name
0030h: 3A 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 ; :
0040h: 20 20 20 20 4D 69 63 72 6F 73 6F 66 74 20 57 69 ; Microsoft Wi
0050h: 6E 64 6F 77 73 20 31 30 20 50 72 6F 0D 0A 4F 53 ; ndows 10 Pro..OS
0060h: 20 56 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 ; Version:
0070h: 20 20 20 20 20 20 20 20 20 31 30 2E 30 2E 31 38 ; 10.0.18
0080h: 33 36 33 20 4E 2F 41 20 42 75 69 6C 64 20 31 38 ; 363 N/A Build 18
0090h: 33 36 33 0D 0A 4F 72 69 67 69 6E 61 6C 20 49 6E ; 363..Original In
00a0h: 73 74 61 6C 6C 20 44 61 74 65 3A 20 20 20 20 20 ; stall Date:
00b0h: 37 2F 32 32 2F 32 30 31 39 2C 20 36 3A 32 38 3A ; 7/22/2019, 6:28:
00c0h: 30 31 20 50 4D 0D 0A 53 79 73 74 65 6D 20 4D 61 ; 01 PM..System Ma
00d0h: 6E 75 66 61 63 74 75 72 65 72 3A 20 20 20 20 20 ; nufacturer:
00e0h: 20 20 4C 45 4E 4F 56 4F 0D 0A 53 79 73 74 65 6D ; LENOVO..System
00f0h: 20 4D 6F 64 65 6C 3A 20 20 20 20 20 20 20 20 20 ; Model:
0100h: 20 20 20 20 20 32 30 4A 4D 30 30 30 39 55 53 0D ; 20JM0009US.
0110h: 0A 53 79 73 74 65 6D 20 54 79 70 65 3A 20 20 20 ; .System Type:
0120h: 20 20 20 20 20 20 20 20 20 20 20 20 78 36 34 2D ; x64-
0130h: 62 61 73 65 64 20 50 43 0D 0A 42 49 4F 53 20 56 ; based PC..BIOS V
0140h: 65 72 73 69 6F 6E 3A 20 20 20 20 20 20 20 20 20 ; ersion:
0150h: 20 20 20 20 20 4C 45 4E 4F 56 4F 20 4E 31 51 45 ; LENOVO N1QE
0160h: 54 38 37 57 20 28 31 2E 36 32 20 29 2C 20 32 2F ; T87W (1.62 ), 2/
0170h: 32 37 2F 32 30 32 30 0D 0A 54 6F 74 61 6C 20 50 ; 27/2020..Total P
0180h: 68 79 73 69 63 61 6C 20 4D 65 6D 6F 72 79 3A 20 ; hysical Memory:
0190h: 20 20 20 20 38 2C 30 37 32 20 4D 42 0D 0A ; 8,072 MB..
%SystemRoot%\System32\wbem\wmic.exe
的输出始终使用Unicode编码,采用UTF-16小端编码,并带有字节顺序标记(BOM)。因此,两个使用的wmic
命令行的输出每个字符占用两个字节。
命令行wmic bios get serialnumber /Format:list
以二进制形式生成输出:
0000h: FF FE 0D 00 0A 00 0D 00 0A 00 53 00 65 00 72 00 ; ÿþ........S.e.r.
0010h: 69 00 61 00 6C 00 4E 00 75 00 6D 00 62 00 65 00 ; i.a.l.N.u.m.b.e.
0020h: 72 00 3D 00 50 00 46 00 31 00 36 00 35 00 48 00 ; r.=.P.F.1.6.5.H.
0030h: 4E 00 4E 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; N.N.............
第一个字节
FF FE
是UTF-16小端字节顺序标记。每个ASCII字符用两个字节(16位)编码,高字节的值为0。换行符是回车(0D 00)和换行(0A 00)。首先输出两个空行,然后是感兴趣数据所在的行,最后再次输出两个空行。
命令行
wmic cpu get name
以二进制形式产生输出:
0000h: FF FE 0D 00 0A 00 0D 00 0A 00 4E 00 61 00 6D 00 ; ÿþ........N.a.m.
0010h: 65 00 3D 00 49 00 6E 00 74 00 65 00 6C 00 28 00 ; e.=.I.n.t.e.l.(.
0020h: 52 00 29 00 20 00 43 00 6F 00 72 00 65 00 28 00 ; R.). .C.o.r.e.(.
0030h: 54 00 4D 00 29 00 20 00 69 00 35 00 2D 00 36 00 ; T.M.). .i.5.-.6.
0040h: 33 00 30 00 30 00 55 00 20 00 43 00 50 00 55 00 ; 3.0.0.U. .C.P.U.
0050h: 20 00 40 00 20 00 32 00 2E 00 34 00 30 00 47 00 ; .@. .2...4.0.G.
0060h: 48 00 7A 00 0D 00 0A 00 0D 00 0A 00 0D 00 0A 00 ; H.z.............
Unicode输出被cmd.exe
重定向到批处理文件的more
,它以每个字符一个字节的方式输出行。但是Windows命令处理器在解释UTF-16 LE编码的行时存在一个错误,可以通过使用以下命令行来查看:
wmic bios get serialnumber /Format:list | more >output.txt
文件
output.txt
包含二进制字节:
0000h: 0D 0D 0A 0D 0D 0A 53 65 72 69 61 6C 4E 75 6D 62 ; ......SerialNumb
0010h: 65 72 3D 50 46 31 36 35 48 4E 4E 0D 0D 0A 0D 0D ; er=PF165HNN.....
0020h: 0A 0D 0D 0A 0D 0A 0D 0A ; ........
每个Unicode编码的回车+换行(0D 00 0A 00)变成ASCII编码的回车+回车+换行(0D 0D 0A)。
这是真正的问题。附加的回车导致使用正则表达式搜索字符串.
来匹配至少包含一个字符的所有行时,空行也会被此正则表达式搜索字符串匹配,而从Unicode转换为ASCII输出时不正确。
如何解释不合法的换行符序列取决于所使用的文本编辑器。大多数文本编辑器将回车符视为行终止符,但findstr
不会这样做。
一种解决方案是显式搜索包含所需数据的行。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
%SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE | %SystemRoot%\System32\findstr.exe /L /C:SerialNumber
%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE | %SystemRoot%\System32\findstr.exe /L /C:Name
echo %USERDOMAIN%\%USERNAME%
) >"%ComputerName%.txt"
endlocal
写入文件%ComputerName%.txt
的数据完全以ASCII编码,每行终止符均为0D 0A
。
关于代码的一些额外信息:
- 不再需要使用命令
more
,因此被省略。将Unicode转换为ASCII采用Windows命令处理器cmd.exe
。
- 该批处理文件未启用延迟环境变量扩展,因为根本不需要。
- 所有可执行文件都使用全名指定。因此,
cmd.exe
无需使用环境变量PATHEXT
和PATH
的值来搜索可执行文件。
- WMIC选项
/Format:list
被/VALUE
选项替代,输出结果相同。
- FINDSTR使用
/L
选项运行,明确指示findstr
进行字面搜索,尽管这在使用/C:
选项时是默认的。
一个更好的批处理文件代码是:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
%SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number: %%J
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name: %%J
echo Domain\User Name: %USERDOMAIN%\%USERNAME%
) >"%ComputerName%.txt"
endlocal
使用WMIC确定的附加数据,并使用ECHO输出,以与systeminfo
的输出具有相同格式的文本文件写入。
注意:最后一个echo
命令行在环境变量USERDOMAIN
或环境变量USERNAME
的值包含)
或&
的情况下不安全。100%安全的方法是:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
(
%SystemRoot%\System32\systeminfo.exe | %SystemRoot%\System32\findstr.exe /L /C:"Host Name" /C:"OS Name" /C:"OS Version" /C:"Original Install Date" /C:"System Manufacturer" /C:"System Model" /C:"System Type" /C:"Total Physical Memory"
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe BIOS GET SerialNumber /VALUE') do if not "%%J" == "" echo Serial Number: %%J
for /F "tokens=1* delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe CPU GET Name /VALUE') do if not "%%J" == "" echo CPU Name: %%J
) >"%ComputerName%.txt"
setlocal EnableDelayedExpansion
echo Domain\User Name: !USERDOMAIN!\!USERNAME!>>"%ComputerName%.txt"
endlocal
endlocal
要理解所使用的命令及其工作原理,请打开
命令提示符窗口,在其中执行以下命令,并完整而仔细地阅读每个命令显示的帮助页面。
echo /?
endlocal /?
findstr /?
for /?
if /?
setlocal /?
systeminfo /?
wmic /?
wmic bios /?
wmic bios get /?
wmic cpu /?
wmic cpu get /?