I want to know how to execute a set of statements or a command in a Windows Batch file or PowerShell script to be executed just once. Even if I run the script multiple times, that particular set of code or program should just run once.
If possible give an example for both Batch files and PowerShell.
In both cases you need to make changes that (a) persist beyond running the batch file or PowerShell script and (b) are visible when you start it the next time. What those changes are would depend on how cluttered you want to leave the system.
One option would be an environment variable. You can set those from batch files with setx or from PowerShell with [Environment]::SetEnvironmentVariable. You should also set them normally to have them in the current session, just to make sure that it can't be called from that session again, too.
if defined AlreadyRun (
echo This script ran already
goto :eof
)
...
setx AlreadyRun 1
set AlreadyRun 1
or
if (Test-Path Env:\AlreadyRun) {
Write-Host This script ran already
exit
}
...
[Environment]::SetEnvironmentVariable('AlreadyRun', '1', [EnvironmentVariableTarget]::User)
'1' > Env:\AlreadyRun
This approach has its drawbacks, though. For example, it won't prevent you from running the same script twice in different processes that both existed at the time the script ran first. This is because environment variables are populated on process start-up and thus even the system-wide change only applies to new processes, not to those already running.
Another option would be a file you check for existence. This has the benefit of working even under the scenario outlined above that fails with environment variables. On the other hand, a file might be accidentally deleted easier than an environment variable.
However, since I believe your batch file or PowerShell script should do something, i.e. have a side-effect, you should probably use exactly that as your criterion for abort. That is, if the side-effect is visible somehow. E.g. if you are changing some system setting or creating a bunch of output files, etc. you can just check if the change has already been made or whether the files are already there.
A probably very safe option is to delete or rename the batch file / PowerShell script at the end of its first run. Or at least change the extension to something that won't be executed easily.
Related
In my certain circumstance an executable I run with
set VAR1=SOMEVAR && process.exe
Does not work.
However, a batch file with
set VAR1=SOMEVAR
works by running it like:
setvar.bat && process.exe
It has been verified process.exe does run in both cases.
The exe I'm using is bacwi.exe and the sourceforge page mentions
"bvlc.bat batch file configures environment variables to use BACnet/IP port 47809 for any subsequent BACnet tools run from that command prompt window, and enables the BBMD Foreign Device Registration."
Are you aware that the first example would include the space between R and && in the value assigned, but the second would not? Given the generality of your question, and your explicit problem description does not work, you're crossing into crystal-ball territory
I'm writing myself a GUI utility for use in a CMD window to navigate between folders,
rather in the style of the old Norton Change Directory utility for DOS.
When run, the app pops up a folder tree to allow the user to select a folder to which
to navigate and then closes and returns to the CMD prompt. At the moment, the way it
works is that it is run as the first command in a "main" batch file. It writes a secondary batch
file, in my app's folder under AppData, containing the commands to change drive and
directory to the folder the user selected, and the main batch file then invokes this
second batch file using CALL.
It works fine, but this way of actually changing the CMD window's current directory
strikes me as inelegant both from the point of view of needing to be run from a batch file
(so that the user's selection can be acted upon after my app has closed) and of
needing the secondary batch file to do the actual navigation.
So, my question is, how can my app send the instructions to the instance of CMD
that owns the window in which the app is run to the folder the user selected? I've tried doing a ShellExecute
of "CMD /K ..." but although that does indeed navigate to the
selected folder, it does so in a new CMD window, not the one my app is run in. The
conceptual gap I have is how to get the current CMD to act on my app's instructions
after my app has terminated.
Fwiw, I thought of trying to write the user's folder selection into an environment variable in the CMD window's environment for the CMD processor to
act upon from there, but this seems to require that the CMD window be opened via "Run as Administrator", which I definitely don't want.
Your program cannot influence the environment variables of the command interpreter because they're separate processes. Your program cannot change the directory of the command interpreter directly, either, because, again, they're separate processes.
You need to use a batch file because the command interpreter executes batch files internally. Since it's all the same process, the batch file has the power to change the current directory, and for that change to remain in effect after the batch file finishes running.
Therefore, you need some way for your interactive program to communicate the directory selection back to the batch file so that it can act on it.
Instead of writing the instructions to another batch file, you could write the result to standard output. Have the batch file capture that output into a variable, and then execute cd on that variable. The batch code would look something like this:
for /f "tokens=*" %%a in ('[select_dir.exe]') do (
set DIRSELECTION=%%a
)
cd /d %DIRSELECTION%
Your Delphi code would look like this:
writeln(selected_dir);
To allow that command to work, you'll need to make sure your program is marked as a console program, as with {$APPTYPE CONSOLE}. If it's not, then the batch file won't receive any output, and probably won't even wait for your program to finish running before proceeding. It's OK for a console program to display a TForm, just like a GUI program.
I'm using this new machine, so as usual I go and set the execution policy so that I can use my profile script, after doing that however powershell now opens all batch files in a new cmd.exe window.
I tried undoing this step but it's still the same so I think it has nothing to do with the script execution policy, also I still have the powershell window in which I originally set the execution policy and this one behaves normally, only new windows have this problem.
I may have installed some software, but nothing is related to windows, and I tried setting the PATH variable to its exact value in the working window but it does not work.
Batch files will open in a new window if the PATHEXT environment variable does not contain '.BAT' as one of the executable extensions.
To check the variable, enter the following at the PowerShell prompt: $env:PATHEXT
I've set an system environment variable called find which points to a batch script. I did this so that in Win command prompt i could type %find% and it would execute my script. It works the only problem is it only works once, my script takes a parameter or requires user input (have tried both), and then it is as if the %find% is temporarily overwritten, and the %find% of course no longer works, until i reopen the command window. Basically it works once and that's it!
How can i make it work every time? i want to execute my script using the environment variable over and over again at will without reloading the command window.
Thanks.
I created a batch script with the following code:
#ECHO off
echo hello
and added a environmental variable called TEST that points to the script. I have no problem executing the script using the environmental variable multiple times.
Can you please provide some information or code of what your script does?
Remember that find is a MS-supplied utility.
Try using a different name. And show us your batch - even possibly describe what happens when it "no longer works." Games of 20-questions are tedious.
The problem is that the Batch script uses a variable with the same name, so after it run for the first time the variable value is overwritten and no longer works. To prevent this to happen, insert a setlocal command at beginning of the Batch file; this way, when the script ends all variables are reset to the values they had before the script run. This method also delete all new variables defined in the Batch script, so it keep the environment clean.
If your intention is to override the behavior of the existing find.exe utility, you could add the location of the script to the global path variable before your System32 folder (where find.exe is located). For example, let's say your script is C:\Scripts\find.bat. If your path variable is currently set to this:
%SystemRoot%\system32;%SystemRoot%
...then you would change it to this:
C:\Scripts;%SystemRoot%\system32;%SystemRoot%
Beware though... doing this could break other scripts that use the find command (if they don't use the absolute path to find.exe).
If you are just wanting an easy way to run your alternate find command, you could just give it a different name as the others have suggested, then add it to the end of the path or place it in the System32 folder. That would save you from having to type the percent signs at least.
I have file which does somethings and it works fine if I run the file manually but it doesn't run when set up in task scheduler.
Batch file is in a folder on desktop on windows 7.
Any feedback will be helpful.
I've even tried this link solution didn't work.
Most likely in this case you need to make sure that the directory the script runs in ("Start in") is set correctly. Usually this is the same directory that contains your script. You can set this in the Scheduled Task's properties.
As a test, try moving the .bat file to a directory with basic permissions (maybe a shared directory for example).
I had the same problem as you. My .bat file was located in a folder with some restrictive permissions on it, so that only my user account could access it. Even though I had set up the task scheduler to use my credentials it still failed. Moving the .bat file to another directory sorted the issue.
I don't know if this will help, but in bashing my head against one problem after another for far too many hours, I finally got my own batch file to work properly as a scheduled task. Some of the things I learned in the process:
If you are the user who has created the scheduled task, you must also be a user who has logged into the system using a password.
Any reference to a file name, inside the batch file, needs to be the last part of fully qualified path, starting with drive letter.
If you do a comparison, like [%flag%] EQU [0], be aware that the "[" and "]" symbols are string literals that are included in the data that gets compared.
If part of your batch file sets a variable and includes a "FOR" loop that calls a subroutine in which you expect to change the variable, you need to make sure that the variable is originally initialized as early as possible in the batch file. That is, something like this:
IF ... (
SET %flag=0
FOR ... (CALL :subr)
IF [%flag%] EQU [1] ( main scheduled-task command goes here)
)
GOTO :eof
:subr
IF ... (SET %flag=1)
:eof
--worked from the command line, but not as a Scheduled Task. I had to move the initialization of %flag to be done before that very-first IF.