【问题标题】:Execute WMIC command in nested for-loop在嵌套的 for 循环中执行 WMIC 命令
【发布时间】:2020-07-15 09:15:36
【问题描述】:

这是我第一次创建批处理文件,我对这种编码语言还比较陌生。我希望创建一个批处理文件来扫描文件夹中的所有 DLL 文件,以检索版本信息并将其写入新的文本文件。嵌套的 for 循环运行良好,但我无法执行 WMIC 命令,您能帮忙吗?

双击运行批处理文件后,我会得到:

    Description = Invalid query
    'WMIC DataFile Where "Name='mydirecotry\myfile.dll'" Get Version'
    Node - myPCname

这是我写的代码:

@echo off

SETLOCAL ENABLEDELAYEDEXPANSION 

FOR %%I in (D:\mydirecotry\*.dll*) DO (

    SET Location='WMIC DataFile Where "Name='%%I'" Get Version'
    ECHO !Location!
    
    For /F "Tokens=1* Delims=" %%A In (!Location!) Do (      <---Where i think it went wrong
    
        For /F "Tokens=*" %%B In ("%%~A") Do Set "pver=%%B" 
        
        ECHO %%I - %pver% >> test.txt
    )
)
pause

提前致谢。

【问题讨论】:

  • 问题在于您的 WMIC 命令,更具体地说,Name WMIC 的值要求名称中的反斜杠用另一个转义。这意味着您将不得不Set "dll=%%A" 然后使用"Name='!dll:\=\\!'"。但是,如果您摆脱所有这些代码并仅使用 WMIC /Output:"test.txt" DataFile Where "Drive='D:' And Path='\\mydirectory\\' And Extension='dll'" Get Name, Version 可能会更好。

标签: batch-file wmic


【解决方案1】:

由于我之前的大部分评论已经在提供的答案中,我决定提供我在该评论中使用的替代方法作为答案。

对于您在问题中提出的任务,您应该能够有一行 ,没有 setfor 命令,只包含:

@"%__AppDir__%wbem\WMIC.exe" /Output:"test.txt" DataFile Where "Drive='D:' And Path='\\mydirecotry\\' And Extension='dll'" Get Name, Version

【讨论】:

    【解决方案2】:

    DLL版本信息收集任务可以通过以下批处理文件完成:

    @echo off
    setlocal EnableExtensions EnableDelayedExpansion
    (for %%I in ("D:\V4-x64\Exe\Bin\*.dll*") do (
        set "FileName=%%I"
        set "FileName=!FileName:\=\\!"
        for /F "skip=1" %%J In ('%SystemRoot%\System32\wbem\wmic.exe DATAFILE where Name^="!FileName!" GET Version 2^>nul') do if defined FileName set "FileName=" & echo %%I - %%J
    )) >test.txt
    endlocal
    

    全限定文件名中的每个反斜杠必须再用一个反斜杠进行转义。这是对使用 DATAFILE 的特殊 WMIC 要求,必须始终使用完整路径指定文件名。

    ' 中指定的命令行由 FOR 在后台运行 %ComSpec% /c 执行,' 中的命令行作为附加参数附加。所以在后台执行,Windows 安装到C:\Windows 命令行:

    C:\Windows\System32\cmd.exe /c C:\Windows\System32\wbem\wmic.exe DATAFILE where Name="D:\\V4-x64\\Exe\\Bin\\FileName.dll" GET Version 2>nul
    

    等号必须用^ 转义才能被解释为文字字符而不是参数分隔符,否则= 将在后台运行cmd.exe 之前被空格字符替换,这将使参数无效wmic.exe.

    重定向运算符&gt; 也必须使用^ 进行转义,以便在完全执行FOR 之前解析FOR 命令行时将其解释为文字字符。

    WMIC 输出使用 UTF-16 Little Endian 编码和字节顺序标记 (BOM) 编码的数据 Unicode。 FOR 无法正确解析 Unicode 输出,因为需要 ASCII/ANSI/OEM 字符编码,即每个字符一个字节,没有空字节。十六进制值0D 00 0A 00 为UTF-16 LE 编码的字节序列,行结束回车+换行被FOR(分别为cmd.exe)解释为0D 0D 0A。因此,在进一步处理剩余字符串之前,在 FOR 删除的实际行结尾处存在错误的回车。

    出于这个原因,WMIC 输出被解释为跳过仅包含字符串 Version 的第一行,因此通过删除前导和尾随空格,首先处理带有版本字符串的第二行。

    当前 DLL 文件的全限定文件名及其版本使用命令 ECHO 输出。此外,删除环境变量 FileName 以确保 WMIC 没有进一步的行输出,包括由 FOR 解释为仅包含回车的行的空行导致再次运行命令 ECHO,循环变量 J 已分配回车符。

    批处理文件不适用于文件名中带有感叹号的 DLL 文件,但这在这里应该无关紧要,因为我从未见过文件名中带有 ! 的 DLL。

    Compo 在评论中提供的另一个解决方案要快得多,并且也适用于文件名中带有! 的 DLL 文件名。

    @echo off
    %SystemRoot%\System32\wbem\wmic.exe DATAFILE Where "Drive='D:' And Path='\\V4-x64\\Exe\\Bin\\' And Extension='dll'" GET Name,Version >"%TEMP%\%~n0.tmp"
    %SystemRoot%\System32\more.com +1 "%TEMP%\%~n0.tmp" >test.txt
    del "%TEMP%\%~n0.tmp"
    

    WMICD:\V4-x64\Exe\Bin 目录中搜索 *.dll 文件,并输出 DLL 文件的全名及其版本,写入一个使用 BOM 编码的 UTF-16 LE 临时文件。接下来使用 MORE 处理此临时文件,跳过标题行和底部的空行,并将输出写入test.txt 作为非 Unicode 文件。临时文件终于被删除了。

    为了完整性:

    @%SystemRoot%\System32\wbem\wmic.exe DATAFILE Where "Drive='D:' And Path='\\V4-x64\\Exe\\Bin\\' And Extension='dll'" GET Name,Version | %SystemRoot%\System32\more.com +1 >test.txt
    

    此命令行生成一个非 Unicode 编码的文本文件 test.txt,其中包含 DLL 文件名和版本的每一行都以 两个 回车符和一个换行符以及两个空底部的行只有一个回车加换行符。因此不建议使用这种单行变体。

    要了解所使用的命令及其工作原理,请打开command prompt 窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

    • call /? ...解释%~n0 ...参数0的文件名,即没有文件扩展名的批处理文件名。
    • del /?
    • echo /?
    • endlocal /?
    • for /?
    • if /?
    • more /?
    • set /?
    • setlocal /?
    • wmic /?
    • wmic datafile /?
    • wmic datafile get /?

    另请参阅 single line with multiple commands using Windows batch file 以了解运算符 &amp; 的说明以及有关 Using command redirection operators 的 Microsoft 文档。

    【讨论】:

    • 感谢您的回答。我尝试了 Compo 和您的两种方法,它们的效果同样好。另外,我感谢您提供的信息,在亲身体验后,它确实提供了更清晰的批处理脚本图片。
    猜你喜欢
    • 2022-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    • 2019-05-11
    相关资源
    最近更新 更多