Многократное тестирование в пакетном файле - REG QUERY - PullRequest
0 голосов
/ 10 декабря 2018

Я работаю над небольшим проектом по развертыванию клиентских приложений в моей компании через GPO (Citrix Receiver и HDX Real Time Engine).

Клиент HDX можно установить, только если Citrix Receiver был установлен заранее.Я также проверяю, установлен ли на компьютере 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% дважды в пакетном скрипте, по-видимому, неудобно.Я не знаю, как решить эту проблему.

Строка, выводимая reg и findstr, например:

    DisplayName REG_SZ  Citrix HDX RealTime Media Engine 2.4

Версия в конце этого значения строки реестранеобходимо обработать, чтобы определить, нужно ли обновить уже установленный клиент Citrix или ничего не делать.

1 Ответ

0 голосов
/ 12 декабря 2018

В общем, лучше использовать if not errorlevel 1 вместо if %errorlevel% EQU 0 или if !errorlevel! EQU 0, потому что этот синтаксис действительно работает везде.if not errorlevel 1 означает ЕСЛИ код выхода предыдущей команды / приложения равен НЕ БОЛЬШЕ ИЛИ РАВЕН 1 или другими словами МЕНЬШЕ * 1 или EQUAL 0, поскольку почти ни одна команда / приложение не завершает работу с отрицательным значением в соответствии с рекомендациями Microsoft.Этот синтаксис работает, так как MS-DOS внутри и снаружи командного блока объясняется с помощью команды IF , выводимой при запуске в окне командной строки if /?.

Оператор перенаправления |должен быть экранирован с ^ только при использовании внутри набора команд FOR .Использование ^| в стандартной командной строке, например, во второй командной строке reg query, приводит к интерпретации вертикальной черты как буквального символа, а REG выводит сообщение об ошибке из-за слишком большого количества параметров.

Но основной причиной того, что код не работает должным образом, является строка:

if %HDX_Version% GEQ 2.4

Внутри командного блока set HDX_Version=%%a, начиная с ( в первой IF строкеи заканчивается совпадением ) в последней, но одной непустой строке, которая определяет эту переменную среды со строкой, считываемой из реестра Windows.Ссылочная переменная %HDX_Version% заменяется командным процессором Windows при разборе всего блока команд перед запуском первого IF .Поэтому, скорее всего, %HDX_Version% заменяется ничем, а выполненное условие IF равно if GEQ 2.4, что приводит к завершению выполнения пакетного файла из-за синтаксической ошибки.Здесь также необходимо использовать задержку расширения переменной среды, т. Е. Использовать синтаксис !HDX_Version! в этой командной строке IF .

Однако код также не будет работать с if !HDX_Version! GEQ 2.4, посколькуОператоры сравнения EQU, NEQ, GEQ и т. д. предназначены для сравнения двух 32-битных значений со знаком целое число .Если один из двух аргументов строки слева и справа, оператор не может быть успешно преобразован в 32-разрядное знаковое целое число , cmd.exe выполняет сравнение строк и сравнивает целочисленное значение, возвращаемое функцией сравнения строк, со значением0 при равенстве, не равном, большем и т. Д. Значения с плавающей запятой, содержащие ., вообще не поддерживаются cmd.exe.Подробнее см. Ответ на Символ, эквивалентный NEQ, LSS, GTR и т. Д. В пакетных файлах Windows .

Я предлагаю следующий код для этой задачи:

@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

Первое и последнее IF условие в этом коде просто для того, чтобы каждый, кто читает этот код, мог запускать его без сообщения об ошибке.

Этот пакетный код работает даже в Windows XPхотя это, скорее всего, не является обязательным требованием для этой задачи.

Эмуляция Windows x86 в Windows x64 должна учитываться при доступе к ключам реестра в HKEY_LOCAL_MACHINE\SOFTWARE в соответствии со статьями Microsoft:

Переменная среды SoftwareKey определяется сначала стандартным ключом реестра HKEY_LOCAL_MACHINE\SOFTWARE.Это правильный ключ для 32-битной Windows и пакетного файла, выполняемого в 32-битной среде версиями x86 cmd.exe и reg.exe, выполняемыми с %SystemRoot%\SysWOW64.Но необходимо добавить \Wow6432Node для доступа к нужному ключу в пакетном файле, выполняемом в x64-версии cmd.exe, начиная с x64-версии reg.exe, хранящейся в %SystemRoot%\System32 в 64-битной Windows.

Переписанный код позволяет избежать определения / изменения переменной среды в командном блоке, указанном в том же командном блоке.Поэтому в этом коде не требуется отложенное расширение переменной среды, которое решает первую главную проблему.

Давайте посмотрим на длинную командную строку:

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

FOR выполняется в отдельном командном процессе, начинающемся с cmd.exe /C и строки в круглых скобках между двумя ' в фоновом режиме, например, командной строки:

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"

REG выводит все ключи реестра для удаления приложений x86 для обработки STDOUT .Вывод сообщения об ошибке для обработки STDERR будет перенаправлен с помощью 2>nul на устройство NUL для его подавления. REG не должно выводить сообщение об ошибке в этом случае.Можно дополнительно использовать /v DisplayName в дополнение к /s в Windows Vista и более поздних версиях Windows, чтобы получить вывод по REG только для всех значений с именем DisplayName.Вывод REG перенаправляется с помощью | для обработки STDIN команды FINDSTR .

FINDSTR поиск вкаждая строка нечувствительна к регистру с регулярным выражением для строки, начинающейся где-либо в строке с DisplayName, имеющей 0 или более символов и строку Citrix HDX.Использование /R /C:"DisplayName.*Citrix HDX" вместо просто "DisplayName.*Citrix HDX" необходимо, так как в противном случае FINDSTR будет выполнять поиск по регулярному выражению в поисках DisplayName и 0 или более символов и строки Citrix ИЛИ строка HDX в любом месте строки, которая здесь не нужна. FINDSTR , мы надеемся, всегда выводим только строку со значением строки, представляющей интерес для обработки STDOUT отдельного командного процесса.

Прочтите статью Microsoft о Использование перенаправления командОператоры для объяснения 2>nul и |.Операторы перенаправления > и | должны быть экранированы с помощью символа вставки ^ в FOR , чтобы интерпретировать их как буквенные символы, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR, который выполняет встроенную командную строку с reg и findstr в отдельном командном процессе, запущенном в фоновом режиме.

FOR захватывает выходные данные, записанные в STDOUT запущенного командного процесса и обрабатывает его построчно, игнорируя пустые строки и по умолчанию также строки, начинающиеся с точки с запятой, которые здесь не встречаются.Другие строки разбиваются на подстроки (токены) с использованием обычного пробела и горизонтальной табуляции в качестве разделителей и присваивают только восемь подстрок с пробелом / табуляцией в указанной переменной цикла I из-за опции tokens=8. FOR никогда не запускает команду SET , если нет строки, по крайней мере, с восемью разделенными пробелом / табуляцией строками.Строка, присвоенная переменной цикла I, присваивается переменной окружения HDX_Version как есть, и выполнение командного файла продолжается в строке под меткой EvaluateVersion.

Второй FOR проверяется, если строка, присвоенная HDX_Version, состоит только из одной или нескольких точек / цифр. FOR выводит сообщение об ошибке в файл ошибок вместо стандартного текстового файла, если строка, назначенная для HDX_Version, содержит любой другой символ, кроме .0123456789, включая ; в начале строки.Выполнение пакетного файла продолжается в конце пакетного файла, поскольку это условие ошибки не может быть обработано автоматически.Вполне возможно, что отображаемая строка изменилась с момента записи этого пакетного файла, который, по крайней мере, должен быть обнаружен и сообщен пакетным файлом.

В противном случае для версии HDX наиболее вероятен формат major . несовершеннолетний еще один FOR используется для разделения версии на две строки, которые являются целыми числами для оценки с помощью целочисленных компараторов команды IF .Дополнительный номер версии не должен существовать, за исключением того, что основной номер версии равен минимальному основному номеру версии.Отсутствующий минимальный вспомогательный номер версии в этом случае интерпретируется как 0, поэтому также необходима установка / обновление клиента Citrix.

Весьма маловероятно, но тем не менее возможно, что строка, назначенная переменной среды HDX_Version, состоит только из одного или нескольких ., в этом случае третий FOR не выполняет какую-либо командную строку в командеблок.Это также приводит к записи сообщения об ошибке в файл ошибок и переходу к концу пакетного файла.

Для понимания используемых команд и их работы откройте окно командной строки, выполните там следующие команды иочень внимательно прочитайте все справочные страницы, отображаемые для каждой команды.

  • echo /?
  • endlocal /?
  • goto /?
  • if /?
  • reg /?
  • reg query /?
  • rem /?
  • set /?
  • setlocal /?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...