Question

Situation:

To keep it simple: I got multiple shortcuts on a network share that starts an VMwareclient application that connects to a console of a virtual machine. The shortcut looks something like this:

\\share\vmware-vmrc.exe -h HOST -u USER -p PASS "[LocalStorage] NAME/NAME.vmx"

But i like to know if someone is already using this console connection, so i can avoid starting this shortcut and choose another machine. So i made an script to do this and changed the shortcut to:

C:\Windows\System32\wscript.exe \\share\start.vbs NAME "[LocalStorage] NAME/NAME.vmx"

This opens a vbscript that runs an batch file silent, so it is not visible for the user.

arg = " " & WScript.Arguments.UnNamed(0) & " """ & WScript.Arguments.UnNamed(1) & """"
CreateObject("Wscript.Shell").Run "client.cmd" & arg ,0,False

This opens client.cmd that operates the launch of the VMwareclient and connects to the given virtual machine and writes a logfile to log which user has the Virtual Machine in use.

@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

The variable %client% contains the first parameter given in the shortcut, it represents NAME.

This all works fine. But there is one problem, at "start /wait :.." the scripts waits till the client application is closed. But when the user logs off or shuts down Windows it force closes the script and it doesn't continue the script to delete the logfile. That causes the logs to be irrelevant because some users who logged off or force closed the script are still present in the logfile as if the virtual machine is still in use.

Problem:

"start /wait" waits till the application is closed, but when a user shuts down windows or logs off the script is force closed and doesn't continue.

Question:

Is there a solution to detect such force close in batch? (probably not) Do i need to switch to VBscript or an other program/script language to accomplish this?

Was it helpful?

Solution

Best option is not to check file existence, but hold a lock on file. If file is locked, it is in use. If it is not locked, you are in the scenario described with a lock file from old connection. Start the following code from two consoles to see how it works.

What it does is redirect output of stream 3 (0=stdin 1=stdout 2=stderr 3-9= for your use) to a lock/log file. This fill will have a lock on it (is is been written) while the code in the parenthesis block is running. Other instance of the batch file trying to run will not be allowed to open the lock file for writting, so the block will not be executed. This case is checked via a environment variable that is asigned a value inside the block. If it has value, the block was executed, if it has no value (not defined) the block has not been executed (the log file is locked by another process).

Stream 3 is used instead of usual output redirection to allow code inside block to echo information to console, but it is not needed.

@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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top