Завершить пакетный / VBS-скрипт при выходе из системы или завершении работы
Ситуация:
Для простоты: у меня есть несколько ярлыков на сетевом ресурсе, который запускает приложение VMwareclient, которое подключается к консоли виртуальной машины. Ярлык выглядит примерно так:
\\share\vmware-vmrc.exe -h HOST -u USER -p PASS "[LocalStorage] NAME/NAME.vmx"
Но я хотел бы знать, если кто-то уже использует это консольное соединение, поэтому я могу избежать запуска этого ярлыка и выбрать другую машину. Поэтому я сделал скрипт для этого и изменил ярлык на:
C:\Windows\System32\wscript.exe \\share\start.vbs NAME "[LocalStorage] NAME/NAME.vmx"
Это открывает VBScript, который запускает пакетный файл без вывода сообщений, поэтому он не виден для пользователя.
arg = " " & WScript.Arguments.UnNamed(0) & " """ & WScript.Arguments.UnNamed(1) & """"
CreateObject("Wscript.Shell").Run "client.cmd" & arg ,0,False
Откроется файл client.cmd, который управляет запуском VMwareclient, подключается к данной виртуальной машине и записывает файл журнала, чтобы узнать, какой пользователь использует виртуальную машину.
@echo off
pushd "%~dp0"
set TIMESTAMP=%TIME:~0,2%:%TIME:~3,2%
set CLIENT=%1
:start
IF EXIST logs\%client% goto msg
echo %username% since %TIMESTAMP% on %DATE% >logs\%client%
start /wait c:\vmwareclient\vmware-vmrc.exe -h HOST -u USER -p PASS %2
del logs\%client%
goto exit
:msg
for /f "delims=" %%x in ('type logs\%client%') do set "type=%%x"
echo wscript.quit MsgBox ("%client% is in use by %type%. Do you like to continue?", 4, "%client% is in use") > yesno.vbs
wscript //nologo yesno.vbs
set value=%errorlevel%
del yesno.vbs
if "%value%"=="6" start /wait c:\vmwareclient\vmware-vmrc.exe -h HOST -u USER -p PASS %2
if "%value%"=="7" goto exit
goto exit
:exit
popd
Переменная% client% содержит первый параметр, указанный в ярлыке, он представляет NAME.
Это все отлично работает. Но есть одна проблема: при запуске / ожидании:.. сценарии ждут, пока клиентское приложение будет закрыто. Но когда пользователь выходит из системы или закрывает Windows, он принудительно закрывает сценарий и не продолжает сценарий для удаления файла журнала. Это приводит к тому, что журналы не имеют значения, поскольку некоторые пользователи, которые вышли из системы или принудительно закрыли сценарий, все еще присутствуют в файле журнала, как если бы виртуальная машина все еще использовалась.
Проблема:
"start / wait" ждет, пока приложение не закроется, но когда пользователь закрывает окна или выходит из системы, скрипт принудительно закрывается и не продолжается.
Вопрос:
Есть ли решение для обнаружения такой силы близко в партии? (вероятно, нет). Мне нужно переключиться на VBscript или другой язык программ / сценариев, чтобы выполнить это?
1 ответ
Лучший вариант - не проверять существование файла, а удерживать блокировку файла. Если файл заблокирован, он используется. Если он не заблокирован, вы находитесь в описанном сценарии с файлом блокировки из старого соединения. Запустите следующий код из двух консолей, чтобы увидеть, как он работает.
Он перенаправляет вывод потока 3 (0= стандартный вывод 1= стандартный вывод 2= стандартный вывод 3-9= для вашего использования) в файл блокировки / журнала. Эта заливка будет иметь блокировку (написана), пока выполняется код в блоке скобок. Другим экземплярам командного файла, который пытается запустить, не будет разрешено открыть файл блокировки для записи, поэтому блок не будет выполнен. Этот случай проверяется с помощью переменной среды, которой присваивается значение внутри блока. Если он имеет значение, блок был выполнен, если он не имеет значения (не определено), блок не был выполнен (файл журнала заблокирован другим процессом).
Поток 3 используется вместо обычного перенаправления вывода, чтобы код внутри блока мог выводить информацию на консоль, но это не нужно.
@echo off
rem Prepare environment
setlocal enableextensions
rem The file used as flag
set "file=client.log"
rem The variable used to test if we got the lock
set "started="
((
rem Mark the process as started
set "started=yes"
rem echo data to screen
echo User %username% will hold the lock
rem save data to log file. It will be on output stream 3
echo %username% >&3
rem Simulate the process to work
pause >nul
rem Redirect output stream 3 to our lock/log file
rem Send stderr to nul to not show errors (ex. file lock fail)
) 3> "%file%" ) 2>nul
rem Check if the process got the lock and has ended
rem OR it couldn't get the lock
if not defined started (
<"%file%" set /p "lockedBy="
setlocal enabledelayedexpansion
echo(Process is locked by !lockedBy!
endlocal
)
endlocal