批处理文件中的多项测试-REG QUERY

时间:2018-12-10 15:41:53

标签: batch-file cmd deployment scripting installation

我正在做一个小项目,以通过GPO(Citrix Receiver和HDX实时引擎)在公司中部署客户端应用程序。

只有预先安装了Citrix Receiver才能安装HDX Client。我还测试了HDX及其版本是否已经安装在计算机上。看看到目前为止我做了什么:

setlocal enabledelayedexpansion

REM Logs Share

set logshare=\\[path_to_logs_share]\


REM Search for Citrix Receiver Client

reg query HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432NODE\Citrix\PluginPackages\XenAppSuite\ICA_Client

REM If Client has been found - search for HDX Client starting by "Citrix HDX"

if %errorlevel% EQU 0 (

    reg query HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall /s /v Displayname ^| findstr /c:"Citrix HDX"

    REM If HDX Client has been detected set a variable containing the version of it

    if !errorlevel! EQU 0 (

        for /F "tokens=8" %%a in ('reg query HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall /s /v Displayname ^| findstr /c:"Citrix HDX"') do set HDX_Version=%%a

        REM If HDX version is greater or eqaul to 2.4

        if %HDX_Version% GEQ 2.4 (
            echo Current version is ok >> %logshare%%ComputerName%.txt
        ) else (
            echo Installation HDX 2.4 in progress >> %logshare%%ComputerName%.txt
        )
    ) else (

        REM In case HDX has not been detected at all - installation begins

        echo Installation HDX 2.4 in progress >> %logshare%%ComputerName%.txt
    )
) else (
REM In case Citrix Client is missing

    echo Client Citrix missing
)

Endlocal

问题在于,在批处理脚本中两次测试%errorlevel%显然很尴尬。我不知道如何解决这个问题。

regfindstr输出的行例如:

    DisplayName REG_SZ  Citrix HDX RealTime Media Engine 2.4

必须处理此注册表字符串值末尾的版本,以确定是否必须更新已经安装的Citrix客户端或什么都不做。

1 个答案:

答案 0 :(得分:1)

通常,最好使用if not errorlevel 1而不是if %errorlevel% EQU 0if !errorlevel! EQU 0,因为此语法实际上可在所有地方使用。 if not errorlevel 1表示前一个命令/应用程序的 IF 退出代码是 NOT GREATER AND EQUAL 1,换句话说就是 LESS THAN strong> 1等于 0,因为根据Microsoft的指南,几乎没有命令/应用程序以负值退出。自命令块内部和外部的MS-DOS以来,这种语法有效的原因是在命令提示符窗口if /?中运行命令 IF 的帮助。

仅在内部命令 FOR 中使用重定向操作符|时,才必须使用^对其进行转义。在标准命令行上使用^|就像在第二个reg query命令行上一样,会导致将竖线解释为文字字符,并且由于太多, REG 会输出错误消息参数。

但是代码无法按预期运行的主要原因是该行:

if %HDX_Version% GEQ 2.4

命令块中有set HDX_Version=%%a,在第一行 IF 上以(开头,在最后一行非空行中以匹配的)结尾,但其中一个非空行使用从Windows注册表读取的字符串定义此环境变量。 Windows命令处理器在运行第一个 IF 之前解析整个命令块时,将变量引用%HDX_Version%替换为Windows命令处理器。因此,极有可能%HDX_Version%被什么都不替换,并且执行的 IF 条件为if GEQ 2.4,由于语法错误,这导致批处理文件执行退出。在此也有必要使用延迟的环境变量扩展,即在此 IF 命令行上使用语法!HDX_Version!

但是,由于比较运算符if !HDX_Version! GEQ 2.4EQUNEQ等主要用于比较两个32-位标记的整数值。如果左右两个参数字符串之一不能成功将运算符转换为32位带符号的整数,则GEQ将运行字符串比较并比较字符串比较返回的整数值函数对值cmd.exe等于,不等于,大于等进行运算。0完全不支持包含.的浮点值。有关更多详细信息,请参见Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files上的答案。

对于此任务,我建议使用以下代码:

cmd.exe

此代码中的第一个和最后一个 IF 条件只是为了使每个阅读此代码的人都可以运行它而不会出现错误消息。

此批处理代码即使在Windows XP上也可以使用,尽管这很可能不是此任务所必需的。

根据Microsoft文章,在访问@echo off setlocal EnableExtensions DisableDelayedExpansion set "LogShare=\\[path_to_logs_share]\" if not exist "%LogShare%" set "LogShare=%TEMP%\" set "MinimumMajorVersion=2" set "MinimumMinorVersion=4" set "SoftwareKey=HKEY_LOCAL_MACHINE\SOFTWARE" if not "%ProgramFiles(x86)%" == "" if not exist %SystemRoot%\Sysnative\cmd.exe set "SoftwareKey=%SoftwareKey%\Wow6432Node" rem Search for Citrix receiver client. %SystemRoot%\System32\reg.exe query %SoftwareKey%\Citrix\PluginPackages\XenAppSuite\ICA_Client >nul 2>nul if errorlevel 1 ( echo Citrix client is not installed.>>"%LogShare%%ComputerName%.txt" goto InstallClient ) rem Search for HDX client starting by "Citrix HDX" if receiver client was found. for /F "tokens=8" %%I in ('%SystemRoot%\System32\reg.exe query %SoftwareKey%\Microsoft\Windows\CurrentVersion\Uninstall /s 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /C:"DisplayName.*Citrix HDX"') do set "HDX_Version=%%I" & goto EvaluateVersion echo HDX version not found under registry key %SoftwareKey%\Microsoft\Windows\CurrentVersion\Uninstall.>>"%LogShare%%ComputerName%.txt" goto InstallClient :EvaluateVersion for /F delims^=.0123456789^ eol^= %%I in ("%HDX_Version%") do ( echo Determined HDX version string "%HDX_Version%" is of unknown format.>>"%LogShare%%ComputerName%_Error.txt" goto EndCitrixCheck ) for /F "tokens=1,2 delims=." %%I in ("%HDX_Version%") do ( if %%I LSS %MinimumMajorVersion% ( echo Determined HDX version %HDX_Version% is too low.>>"%LogShare%%ComputerName%.txt" goto InstallClient ) if %%I EQU %MinimumMajorVersion% ( if "%%J" == "" ( if not %MinimumMinorVersion% == 0 ( echo Determined HDX version %HDX_Version% has no minor version number.>>"%LogShare%%ComputerName%.txt" goto InstallClient ) ) else if %%J LSS %MinimumMinorVersion% ( echo Determined HDX version %HDX_Version% is too low.>>"%LogShare%%ComputerName%.txt" goto InstallClient ) ) echo Determined HDX version %HDX_Version% is okay.>>"%LogShare%%ComputerName%.txt" goto EndCitrixCheck ) echo Determined HDX version string "%HDX_Version%" is of unknown format.>>"%LogShare%%ComputerName%_Error.txt" goto EndCitrixCheck :InstallClient echo Installation of HDX in progress ...>>"%LogShare%%ComputerName%.txt" rem Add here the command lines to install the Citrix client. :EndCitrixCheck if "%TEMP%\" == "%LogShare%" del "%LogShare%%ComputerName%.txt" endlocal 下的注册表项时,必须考虑Windows x64仿真下的Windows x86:

首先使用标准注册表项HKEY_LOCAL_MACHINE\SOFTWARE定义环境变量SoftwareKey。这是从HKEY_LOCAL_MACHINE\SOFTWARE执行的cmd.exereg.exe的x86版本在32位环境中执行的32位Windows和批处理文件的右键。但是有必要附加%SystemRoot%\SysWOW64来访问由\Wow6432Node的x64版本执行的批处理文件上的右键,起始于同时存储在cmd.exe中的reg.exe的x64版本, Windows。

重写的代码避免了在同一命令块中引用的命令块中定义/修改环境变量。因此,此代码不需要延迟的环境变量扩展,从而解决了第一个主要问题。

让我们看看长长的命令行:

%SystemRoot%\System32

FOR 在单独的命令过程中执行,该过程以for /F "tokens=8" %%I in ('%SystemRoot%\System32\reg.exe query %SoftwareKey%\Microsoft\Windows\CurrentVersion\Uninstall /s 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /C:"DisplayName.*Citrix HDX"') do set "HDX_Version=%%I" & goto EvaluateVersion 和背景中两个cmd.exe /C之间的圆括号中的字符串为例,例如命令行:

'

REG 为x86应用程序输出所有卸载注册表项,以处理 STDOUT 。输出用于处理 STDERR 的错误消息将通过C:\Windows\System32\reg.exe query HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall /s 2>nul | C:\Windows\System32\findstr.exe /I /R /C:"DisplayName.*Citrix HDX" 重定向到设备 NUL 进行抑制。在这种情况下, REG 不应输出错误消息。在Windows Vista和更高版本的Windows上,除了2>nul之外,还可以使用/v DisplayName来仅由名称为/s的所有值通过 REG 获得输出。 REG 的输出使用DisplayName重定向,以处理命令 FINDSTR STDIN

FINDSTR 在不区分大小写的每行中使用正则表达式搜索以|开头的,包含0个或更多字符和字符串DisplayName的字符串。必须使用Citrix HDX而不是/R /C:"DisplayName.*Citrix HDX",因为否则 FINDSTR 会运行正则表达式查找来搜索"DisplayName.*Citrix HDX"和0个或更多字符以及字符串{ {1}} 字符串DisplayName在行中不需要的任何地方。希望 FINDSTR 输出总是仅包含感兴趣的字符串值的行,以处理单独命令过程的 STDOUT

阅读有关Using Command Redirection Operators的Microsoft文章,以获取CitrixHDX的解释。重定向操作符2>nul|必须用 FOR 命令行上的脱字符号>进行转义,以在Windows命令解释器处理此命令行时将其解释为原义字符。在执行命令 FOR 之前,该命令在后台启动的单独命令进程中使用|^执行嵌入式命令行。

FOR 捕获写入启动命令过程的 STDOUT 的输出,并逐行处理,而忽略空行,并且默认情况下还以分号开头的行这里不会发生。其他行使用常规空格和水平制表符作为分隔符,分成子字符串(令牌),并且由于选项reg仅将八个空格/制表符分隔的子字符串分配给指定的循环变量findstr。如果没有一行包含至少八个空格/制表符分隔的字符串,则 FOR 永远不会运行命令 SET 。分配给循环变量I的字符串原样分配给环境变量tokens=8,并且批处理文件的执行在标签I下面的行上继续。

第二个 FOR 验证分配给HDX_Version的字符串是否仅包含一个或多个点/数字。如果分配给EvaluateVersion的字符串包含HDX_Version以外的任何其他字符,包括HDX_Version,则 FOR 将错误消息输出到错误文件,而不是标准文本文件在字符串的开头。批处理文件的执行在批处理文件的末尾继续,因为无法自动处理此错误情况。自编写此批处理文件以来,显示的字符串可能已更改,至少应由该批处理文件检测并报告。

否则,HDX版本最有可能是格式主要 .0123456789 次要,另外一个 FOR 用于拆分版本分为两个字符串,它们是整数,可使用命令 IF 的整数比较器进行评估。次要版本号不得存在,除非主版本号等于最小主版本号。在这种情况下,缺少的最小次要版本号被解释为;,因此也需要安装/更新Citrix Client。

不太可能,但是仍然有可能分配给环境变量.的字符串仅包含一个或多个0,在这种情况下,第三个 FOR 不会执行命令块中的任何命令行。这还会导致将错误消息写入错误文件,并跳转到批处理文件的末尾。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • HDX_Version
  • .
  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • reg /?
  • reg query /?
  • rem /?