Batch file 批处理文件中嵌套for循环的正确语法

Batch file 批处理文件中嵌套for循环的正确语法,batch-file,cmd,registry,Batch File,Cmd,Registry,我试图在许多服务器上查询已安装应用程序的注册表值。我可以硬编码的服务器,并有很多重复,它似乎工作。但有时服务器列表可能会改变,我想采用更合理的模块化方法 因此,我可以提供一个带有服务器名称列表的测试文件,然后查询所有这些服务器的注册表值,并将它们输出到日志文件中 我认为问题肯定出在我的循环/变量存储上。不确定到底发生了什么,但似乎一旦我得到一组注册表值,就会为每个服务器输出这些值,而不管它们各自的注册表值如何 我对这种脚本编写没有太多的经验,所以我一直在尝试和错误地将它们混合在一起,下面是我到目

我试图在许多服务器上查询已安装应用程序的注册表值。我可以硬编码的服务器,并有很多重复,它似乎工作。但有时服务器列表可能会改变,我想采用更合理的模块化方法

因此,我可以提供一个带有服务器名称列表的测试文件,然后查询所有这些服务器的注册表值,并将它们输出到日志文件中

我认为问题肯定出在我的循环/变量存储上。不确定到底发生了什么,但似乎一旦我得到一组注册表值,就会为每个服务器输出这些值,而不管它们各自的注册表值如何

我对这种脚本编写没有太多的经验,所以我一直在尝试和错误地将它们混合在一起,下面是我到目前为止所做的。请指出我犯过的任何糟糕的语法错误

因此,本质上这是为了找到安装在每台服务器上的McAfee扫描引擎版本。McAfee控制台本身的报告并不总是可靠的,我想检查内容是否已成功下载到每台服务器

创建完整引擎版本需要两个注册表值,因此我需要将这两个值都提取出来,然后将它们组合成一个字符串

目前,我确实得到了一个看起来正确的输出,但它并不代表实际安装到每个服务器上的内容。这就像一个值被提取然后被复制

另外,这似乎只有在命令行中执行时才起作用。在运行它的前1-2次时,不会提取任何值。感觉我离解决问题的办法还很远

SET LOGFILE=C:\LogFile.log
For /f %%i in (servers.txt) DO (
for /f "tokens=3" %%a in ('reg query \\%%i\HKLM\SOFTWARE\McAfee\AVEngine /v EngineVersion32Major ^| find /i "EngineVersion32Major"') do set /a major=%%a
for /f "tokens=3" %%b in ('reg query \\%%i\HKLM\SOFTWARE\McAfee\AVEngine /v EngineVersion32Minor ^| find /i "EngineVersion32Minor"') do set /a minor=%%b
echo %%i: %major%.%minor% >> %LOGFILE%
)
预期的输出如下所示:

server1 : 5900.5647
server2 : 6000.4589
server3 : 5900.5647
server4 : 5900.5647

为您能提供的任何帮助干杯。

语法与
无关,但与
cmd
如何解析脚本无关。看

cmd
解析块(parens中的任何内容)时,将其作为一行进行处理。因此,它将任何
%var%
扩展到其实际内容。在退出块之前,不会考虑对其所做的更改。要检索块中的新内容,必须启用
延迟扩展
,这将强制解析器在每次迭代中对其进行评估。此外,语法必须从
%var%
更改为
!瓦尔

在这里,还从
set
命令中删除了
/a
开关,因为您没有进行计算,您可能会得到意想不到的结果(假设一个小版本等于
0080
,它将被视为八进制(无效)并会破坏脚本)。另外,请注意用引号括起来的var名称和var内容(
set“minor=%%b”
),以避免不需要的尾随/前导空格

此外,我认为您不需要
^ | find/I“EngineVersion32Major
部分,因为名为
EngineVersion32Major
的键可能只包含您正在查找的内容。此外,请将数据括在引号中(永远不知道何时会出现空格)。您还可以通过
“skip=1 tokens=3”更改
避免处理标题
reg
回波

因此

此外,无论是否启用延迟扩展(请注意双百分号),这都在块内工作

另一个问题是,无论何时在块中使用重定向,系统都会打开和关闭文件(或流)

但是

处理块中的所有命令,因此文件只打开和关闭一次。这可能会提高性能,特别是对于大文件

顺便说一句

(
  ...
  ...
)>>"%LOGFILE%" 

它与
for
语法无关,而是与
cmd
如何解析脚本有关。看

cmd
解析块(parens中的任何内容)时,将其作为一行进行处理。因此,它将任何
%var%
扩展到其实际内容。在退出块之前,不会考虑对其所做的更改。要检索块中的新内容,必须启用
延迟扩展
,这将强制解析器在每次迭代中对其进行评估。此外,语法必须从
%var%
更改为
!瓦尔

在这里,还从
set
命令中删除了
/a
开关,因为您没有进行计算,您可能会得到意想不到的结果(假设一个小版本等于
0080
,它将被视为八进制(无效)并会破坏脚本)。另外,请注意用引号括起来的var名称和var内容(
set“minor=%%b”
),以避免不需要的尾随/前导空格

此外,我认为您不需要
^ | find/I“EngineVersion32Major
部分,因为名为
EngineVersion32Major
的键可能只包含您正在查找的内容。此外,请将数据括在引号中(永远不知道何时会出现空格)。您还可以通过
“skip=1 tokens=3”更改
避免处理标题
reg
回波

因此

此外,无论是否启用延迟扩展(请注意双百分号),这都在块内工作

另一个问题是,无论何时在块中使用重定向,系统都会打开和关闭文件(或流)

但是

处理块中的所有命令,因此文件只打开和关闭一次。这可能会提高性能,特别是对于大文件

顺便说一句

(
  ...
  ...
)>>"%LOGFILE%" 

请使用
搜索
功能查找有关
延迟扩展
的许多SO文章

在您的案例中,最简单的方法是使用

call echo %%i: %%major%%.%%minor%% >> %LOGFILE%

请使用
搜索
功能查找有关
延迟扩展
的许多SO文章

在您的案例中,最简单的方法是使用

call echo %%i: %%major%%.%%minor%% >> %LOGFILE%

明亮的谢谢你讲了这么多细节。正如我所说,我对这方面比较陌生,只是把不同的东西混合在一起。干杯,太棒了!谢谢你讲了这么多细节。正如我所说,我是
(
  ...
  ...
)>>"%LOGFILE%" 
call echo %%i: %%major%%.%%minor%% >> %LOGFILE%