В общем, лучше использовать 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 /?