Issues with Batch Taskkill of Parent MSAccess Process - vba

Process Tree:
I have an MS Access version control macro that checks users current file version on open, and if not up-to-date, the macro launches a batch file that 1) should delete their current file, and then 2) copies the up-to-date front-end version from the network and pastes it on their local system.
My issue:
Everything works EXCEPT for the deletion of the users original file. Since this file is the parent process of the batch file I haven't found a way to Kill the task so it can be deleted.
Current Code:
TASKKILL /F /fi /IM MSACCESS.EXE /T
del "%originalFile%"
**I thought maybe I was having issues because the batch was a child of the Access process, so I've also tried with no luck:
TASKKILL /F /fi /IM MSACCESS.EXE
I always get the error:
ERROR: Invalid syntax. Value expected for '/fi'.
Its been a long day, so I assume I'm missing something simple and would love an extra set of eyes. Any help would be greatly appreciated!

I have a similar setup, but without TASKKILL.
Directly after launching my update batch, I do Application.Quit
' If need to update
Shell UPDATE_BATCH, vbNormalFocus
Application.Quit
And in the update batch, I wait for 3 seconds so that Access has enough time to exit (and release the lock on the frontend).
sleep.exe 3
REM ... copy new frontend ...
sleep.exe 1
REM ... start MSACCESS command line ...
How to "sleep"? See here: SLEEP.exe (2003 Resource Kit) for different variants.

Related

Set Shell Variable from ConsoleApplication in VB.Net

I have a batchfile that run a vb.net Console App.
I need to change some var's e.g. "vbrun" from the current commandline to use it in other batch files, they run after the Console App
as example test.bat
#echo off
set vbrun=true
myVBTool.exe
echo %vbrun%
In windows, the environment variables are stored inside a memory area called the environment block. This memory is not shared, each process has its own copy. When a parent process starts a child process, the parent customize the environemtn block of the child or give to it a copy of its own environment block.
But you need the inverse. You want to change the environment of the parent process (cmd.exe) from a child process (myVBTool.exe).
In short, no, this can not be done.
But, of course, a process can change its own environment. In your case, you need a way for your tool to indicate to its parent process that the variable needs to be changed.
You can set a return value for your application that will be stored as errorlevel and depending on it set your variable
rem ....
myVBtool.exe
if errorlevel 1 set "vbrun=false"
rem ....
Or your application can write to stdout and the batch file can process this output
for /f "delims=" %%a in ('myVBTool.exe') do set "vbrun=%%a"

How do I reopen programs using CMD from a list or variable

I have a section of code;
:check
for /f "tokens=1* delims==" %%A in ('"wmic process get description, commandline /format:list"') do (
if "%%A"=="CommandLine" (
set "cmd=%%B"
) else if "%%A"=="Description" (
set "desc=%%B"
setlocal enableDelayedExpansion
set "desc=!desc:~0,-1!"
set "cmd=!cmd:~0,-1!"
if /i !desc! == %1 (
echo !cmd! >>C:\test.txt
)
endlocal
)
)
goto:eof
Which pretty much works (this is actually a function called from withing a batch file e.g
call:check processname1.exe
call:check processname2.exe
call:check processname3.exe
etc...
What I'd like to do (if possible), is, insead of echoing to a file, I'd like to be able to create 2 variables. something like;
processname1.exe processname3.exe <-- (for each process 'checked' if it IS running, append its name to this variable)
commandlinepath1 commandlinepath2 <-- (for each process 'checked' if it IS running, append its path to this variable)
If this is possible, and I can then call on these variable later in my script, I'd like to be able to tskill the running processes (easy enough if the variables above can be made), then later on, RE-OPEN these processes (using and command line parameter that were in the original path. This is where I'm lost.
My code above (writing to a file). will give results like;
"C:\somefolder\someexe.exe" -some_parameter
"C:\some therfolder\someotherexe.exe"
"C:\another older\anotherexe.exe" param1 param2
But What I need to do, is take each line of this file (or variable if possible), and run them (if I copy each line into the RUN command of windows, it works, but doing it through CMD it doesn't).
I've tried using a for loop to open the files, and it does, except the script waits for the process to finish beford continuing (and these process won't end, since they are applications). If I try to use START .. then it loads a new CMD window??
What I need to do (in case there is a better option) is
for a pre-determined set of processes, check to see if they are running
kill the ones that are (if they are not, fine ignore it)
delete some files (I can do this, the reason for killin the processes is they hold the files open, preventing deletion)
Re-open all the programs that were originally running
Thanks..
Not a direct answer, but since you already use wmic, maybe using its built in capabilities (query, start & stop) would make your goal easier to achieve?
I come up with the following:
#echo off
setlocal
for %%C in (notepad.exe) do (
for /f "skip=1 tokens=2 delims==" %%F in ('wmic process where description^="%%C" get commandline /format:list') do (
REM required to normalize unicode output from WMIC
set commandline=%%F
REM '\=\\' required as wmic treats \ as escape char in query
call wmic process where commandline='%%commandline:\=\\%%' terminate
REM do your work here
call wmic process call create '%%commandline%%'
)
)
What it does:
First for supplies process names. In my example, it simply is notepad.exe, but you could call with a list: for (process1 process2 process3), or replace it with for /f to supply values from file. If you want to use quoted names, you would have to remove quote from next line (description^="%%C").
Second for does real work: it gets a list of all processes matching description and sequentially stops and starts each of them.
To try it, simply put it in a batfile.bat, open notepad(s) and execute.
Note: if you open notepad with a file, either specify an absolute path, or do it via explorer (double click). The issue here is of current directory - which you could also stumble upon if any of your processes does reference relative paths (unlikely, but not impossible)
Last but not least - doing that in powershell would be the easiest, shortest and most reliable.

Creating a bat file which executes SQL scripts

I have a folder into which a number of MSQL scripts get dropped into after each weekly sprint. For example, 10 scripts were placed into the folder today. I had to then open each script individually and run it against the applicable database. The database that it needs to be run against is in the name of the file.
e.g. [2] [CRMdata]UpdateProc.sql
The [2] represents the sequence in which it is run, so script [1] needs to be run before it.
[CRMdata] is the database I have to run it against.
This process is very tiresome, especially if there are 50 scripts to run sequentially.
I was wondering if there was an easier way to do this?
Perhpas a .bat file, which reads the filename, and executes the scripts sequentially based on the script number, as well as executing it against the database specified in the file name.
Any help is much appreciated.
Thanks.
First, when you need to run things, consider using SQL Server Job Agent. This is a good way to schedule simple things.
For a task like this, I would recommend PowerShell in combination with "sqlcmd". This command is actually the answer to your question, since it will run scripts from the command line.
However, go a step further. Schedule a job that runs once per week (or whenever you want it run). Have it consist of one step, a PowerShell script. This can then loop through all the scripts in the directory, extract the file name from the name, and run the script using sqlcmd. Along the way, also log what you are doing in a table so you can spot errors.
I don't know anything about executing SQL with MSQL. You will have to work out how to run each script against the proper database using whatever command-line utility is provided for MSQL.
I can help you with a batch file that will sort the SQL files in the correct sequence order, and parse out the name of the database.
The job is much easier in batch if the sequence numbers are zero prefixed to be a constant width. I'm assuming it is OK to rename the files, so that is what this solution does.
I also assumed you will never have more than 999 files to process. The code can easily be modified to handle more.
Some changes will have to be made if any file names contain the ! character because delayed expansion will corrupt the expansion of the FOR variables. But that is an unlikely problem.
#echo off
setlocal enableDelayedExpansion
:: Change the definition to point to the folder that contains the scripts
set "folder=sqlCodeFolder"
:: The mask will only match the pattern that you indicated in your question
set "mask=[*] [*]*.sql"
:: Rename the .sql files so that the sequence numbers are zero prefixed
:: to width of 3. This enables the default alpha sort of the directory to be
:: in the proper sequence
for /f "tokens=1* delims=[]" %%A in ('dir /b "%folder%\%mask%"') do (
set seq=00%%A
ren "%folder%\[%%A]%%B" "[!seq:~-3!]%%B"
)
::Process the renamed files in order
for %%F in ("%folder%\%mask%") do (
for /f "tokens=2 delims=[] " %%D in ("%%~nF") do (
rem %%F contains the full path to the sql file
rem %%D contains the name of the database, without enclosing []
rem Replace the echo line below with the proper command to run your script
echo run %%F against database [%%D]
)
)

Start /WAIT Program.bat

I am trying to write a batch file that starts another batch file, waits for that batch file to complete its job, and then continue once that other batch file has exited. However, when I manually close the batch file launched by the first batch file, it comes up with a prompt saying:
^CTerminate batch job (Y/N)?
Is there a way to automatically select 'N', because it needs to delete some temporary files on exit.
Purpose/Premise of Script: To be able to remove a flash drive and lock the station (hence copying files to external source).
Summary of Script:
Program Copies files to %homedrive%
Program launches another script (one of the files copied to homedrive)
After that program quits, it deletes the copied files
Solutions Tried:
Different command switches inside of START /WAIT +/I +/B (Adding /I
or /B did not produce anything useful)
Using /C and /K switches after the START /WAIT program.bat +/C +/K
(had no affect)
Well, you could use echo n | program.bat to automatically respond n to ^CTerminate batch job (Y/N)?, but an easy way to fool this method is to hit and keep pressed [Ctrl]-C.
There simply is no reliable way to disable the interruption of any program (much less a batch file). What stops the user from just closing the window?
You would want a command like this:
start /wait program.bat|echo n>nul
">nul" will hide the "n" that shows up afterwards. But there doesn't seem to be a way to stop "^C" from showing up.

Can I control a variable from one batch file with another?

I'm using two batch files, and I need to control variables in one of them, from the other. Is this possible?
You cannot directly influence one process' environment from another process. You know, we've kinda outgrown ye olde days of real mode by now :-)
This all depends a bit on what you're trying to achieve here. If you're calling one batch file from the other, as in
call second.cmd
then the called one »inherits« the environment of the parent batch. So any variable you defined earlier will continue to exist in the child batch. You cannot propagate changes up to the parent, though and you cannot change a variable in the child batch after it has been started, too. It might still be a viable option if all you need is to perform some one-time initialization before starting the child batch.
What you could do is to agree on a file used by both batch files that they will use as a means of communicating with each other, likely located in the temporary directory. Each batch file would need to regularly check for the file to be present and if so, read it and update its variables accordingly. For that to succeed you need points in the batch files where they can look for that file. The simplest would be two files that simply do a bit communication with each other:
The code for that is here:
callchat.cmd:
#echo off
set SENDFILE=%TEMP%\1.out
set RCVFILE=%TEMP%\1.in
start call chat.cmd
ping -w 5000 -n 1 123.45.67.89 >nul 2>&1
set RCVFILE=%TEMP%\1.out
set SENDFILE=%TEMP%\1.in
start call chat.cmd
chat.cmd:
#echo off
setlocal enabledelayedexpansion
rem Prevent direct use
if not defined SENDFILE goto :eof
if not defined RCVFILE goto :eof
set MESSAGE0=I don't know what to say ...
set MESSAGE1=Foo
set MESSAGE2=Bar
set MESSAGE3=Hey there!
set MESSAGE4=Meow.
:loop
rem wait a bit
ping -n 1 -w 1000 123.45.67.89 >nul 2>&1
rem look whether we need to show something
if exist %RCVFILE% (
for /f "delims=" %%l in (%RCVFILE%) do echo Received message at %TIME% - %%l
del "%RCVFILE%"
)
rem randomly send out messages. Roughly ever three times we try this
set /a msg=%random% %% 5
set msg=!MESSAGE%msg%!
if %RANDOM% LSS 10000 (
>>%SENDFILE% echo(%msg%
echo(Sent message "%msg%"
)
goto loop
The batch file is started twice, with different input/output files – in fact, the reversed role of the files from the first invocation. Then it's little more than an endless loop that looks into its input file and read what's in there and writing stuff to its output file (which is the input file for the other batch).
I had to introduce a delay in starting both of them to avoid the PRNGs for both being exactly the same. It also reduced the cases where access to the file failed (this could probably be alleviated by renaming it before reading from it – or, if writing longer content, renaming it to its final name only after being done writing). It's just a simple demo application to show you that it might be possible that way.
To set environment variables you wouldn't print out what's in the file but call it as a batch file, for example:
if exist %RCVFILE% call %RCVFILE%
It would need the proper extension for that, though. You can also read it line by line and have each line contain a VARIABLE=VALUE pair:
if exist %RCVFILE% call for /f "tokens=1* delims==" %%a in (%RCVFILE%) do set %%a=%%b
The techniques mentioned above for improving reliability when accessing the same file from two different programs still apply.
As mentioned, this is only a rough idea how you could operate, iff I understood your question correctly.