Run a python script in virtual environment from windows task scheduler - python-3.x

I'm trying to set up a recurring Python task through windows task scheduler.
I have had success when I input the path to 'python.exe' and provide the script's path as a parameter to windows task scheduler (see screenshot below)
However, I want to be able to choose a particular virtual environment in which to run the script. I don't have much knowledge of venv, and I typically use it by opening cmd and running Scripts\activate.bat in the desired virtual environment directory.
How can I accomplish 'run task x in venvxxx every 24 hours' using windows task scheduler?

Create batch file with these commands:
c:\__full_path_to_virtualenv__\Scripts\activate.bat && python __full_path_to_python_script__.py
&& means run command2 if command1 completed successfully.
Then set that batch file as script to run. You don't need to set any additional arguments in task scheduler (or you can set them in batch file anyway) and can set Start in if script has to read/write from specific directory and uses relative paths.

Though the answer by mx0 above seems to work, I have set up Task Scheduler to run a flask web app on bootup. In this case, manual starting works fine, but manual ending does not. Ending the task kills the cmd.exe task that sets up the virtual environment, but the python.exe continues to run.
The solution that I found worked was from this reddit post which skips the virtual environment activation to call the python executable directly:
path\to\venv\Scripts\python.exe path\to\script.py
I'm not sure how robust this will be, but at least this way ending the task will end the python.exe

This is more verbose but very easy to understand, and - I found the most important - much easier than using Windows Task Scheduler settings when you have lots of scripts. To create another you just copy the .bat file and change one line.
Save this as a .bat file and point to it under Actions > Start a Program > Program/Script:, with no arguments or "Start in" necessary.
set original_dir=%CD%
set venv_root_dir="C:\Python-Venvs\env-name"
cd %venv_root_dir%
call %venv_root_dir%\Scripts\activate.bat
python your_script.py <arg1> <arg2>
call %venv_root_dir%\Scripts\deactivate.bat
cd %original_dir%
exit /B 1
For an installed command-line program, you can replace python your_script.py <arg1> <arg2> ... with <program name> <arg1> <arg2> ....
In addition it's simple to add another script on the following line, rather than attempting to parse sequential scripts into a one-liner for Task Scheduler.

I tried with mx0's answer and it works fine as long as your script does not take too long to finish.
I use a different approach in the task scheduler instead using batch files:
In "Program/script" textbox you set the path to Python executable (in my case is inside the virtualenv folder).
"Add arguments" => Just the name of your Python script (name.ppy).
"Start in" => The full path of your Python script (without the name.py).
This way the script runs and wait until the end.

My solution is almost identical to mx0, but I've added an extra step to ensure environment parameters each time. Edit the path/to/app for the app_path variable.
It may be a little redundant to check the environment setup every time, but I like ensuring my environment is set.
Simply schedule the execute_app.bat file or run in the cmd prompt. Deactivate command is not needed unless running from an Anaconda prompt. If you use a full path for path/to/app this file can be executed from any directory. I also have a Linux solution using execute_app.sh file below from a terminal.
This answer has been edited to simplify, and to use variables to make this easier to adapt to new projects.
App structure:
app/bin/app.py
app/bin/execute_app.bat
app/env/requirements.txt
# execute_app.bat file
# windows solution
SETLOCAL
set app_path=path/to/app
set env_path=%app_path%/env
set activ=%env_path%/Scripts/activate.bat
set req=%env_path%/requirements.txt
set app=%app_path%/bin/app.py
py -m venv %env_path% && %activ% && python -m pip install --upgrade pip && pip install -r %req% && python %app%
ENDLOCAL
#!/bin/bash
# execute_app.sh file
# Linux solution
app_path='path/to/app'
env_path=$app_path'/env'
activ=$env_path'/bin/activate'
req=$env_path'/requirements.txt'
app=$app_path'/bin/app.py'
python3 -m venv $env_path &&
. $activ &&
python3 -m pip install --upgrade pip &&
pip install -r $req &&
python $app &&
deactivate

The selected answer for this question is not correct. If you review the comments, you'll see the problem.
My answer builds off of #Nick P's answer (the #2 answer currently). His batch file will work, but you'll want to change the exit code from 1 to 0 if you want Windows Task Scheduler to report the task completed successfully. Also, simply calling the .bat file on the "Program/Script" line will not work. Instead, you need to put the name of your shell as the "Program/Script" to run (for instance, cmd), then put "/c name-of-batch-file.bat" goes in the "Add arguments (optional):" field. And finally, put the path to the batch file (minus the file name) in the "Start in (optional):" field.
It should look something like this:

REM Windows batch script to run 1+ Python program/scripts, sequentially, within
REM their virtual environment. This can be called from Windows Task Scheduler.
set original_dir=%CD%
set venv_root_dir="C:\Users\myUsername\myProjects\nameOfProject"
cd %venv_root_dir%
call %venv_root_dir%\Scripts\activate.bat
python nameOfPythonProgram.py
call %venv_root_dir%\Scripts\deactivate.bat
cd %original_dir%
exit /B 1
Copied this from nmpowell on github and it works fine. Run from task scheduler

Solution
Patching the path is all necessary.
The quick way would be a bat script that source environment activation script at the beginning
#call PATH_TO_MY_VENV/bin/activate.bat
python app.py
Proceeding Problem
Later you will realize that the python job starts fine, but won't stop when Windows Scheduler stop it.
When taskengine.exe decides to stop the job, the intermediate cmd.exe (bat script) process is killed and the Python.exe will be left straw. since the cmd.exe(bat script) won't signal python.exe to stop on exit.
Final Solution
Let Windows Task Scheduler or taskengine.exe launch python.exe directly without a middle-man script.
Previous answers launch python.exe directly with py script, this works for simple modules, but not for some binary module in conda environment.
For binary modules in conda to work, you can create a utility module named e.g. patch_conda_path to patch PATH variable in os.environ based on sys.base_exec_prefix. Copy the patching work that activate.bat does, just in python.
below example has been tested for conda virtual environment:
import is, sys
conda_base = sys.base_exec_prefix
subps = [";", "library\\mingw-w64\\bin;", "library\\usr\\bin;", "library\\bin;", "scripts;", "bin;", "condabin;"]
conda_paths = ""
for p in subps :
_p = os.path.join(conda_base, p)
if _p in os.environ["PATH"]:
continue
else:
conda_paths += _p
os.environ["PATH'"] = conda_paths + os.environ["PATH"]
Import this module at the beginning of your main script.
import patch_conda_path
... original main script ...
In task scheduler set
program to ... conda environment path...\python.exe,
arguments to your py script file name and
start in to your py script folder.

Related

CRON job is not executing Amass exe as a subprocess?

On Ubuntu 20.04, I have setup amass.exe to detect subdomains through the CRON system, but Amass is only working through manual execution of .py script, not through CRON.
Installation of Amass as follows -
sudo apt update
Sudo apt install snapd
sudo snap install amass
# amass.exe added to PROJ ROOT DIR.
The subdomains.py script invokes the amass exe through a subprocess call as follows:
import subprocess
domain = 'somedomain'
cmd = f'amass enum -passive -d {domain} -json {domain}.json'
subprocess.run(cmd, shell=True)
# on running subprocess.. a JSON file is created which is not taking place through CRON job.
Rest all other cron jobs with sub-processes are working fine except for Amass, where the .exe file permissions might not be accessible to the CRON handler.
Would you please advise what issue it could be in Amass script? Thanks.
Environmental Variables Missing
I don't know if the answer is still needed, but check if you've placed the proper environmental variable in the cronjob.
If not given, then just give the 'PATH' variable and put the cronjob again.
Also, you can add the Path in the python code, in case you don't wanna give the path in cronjob by using sys.path.insert(0,"") (before the subprocess statement).

Windows Task Scheduler to run Python Scripts

I am using VS Code to execute a python code. I want to automate this windows task scheduler,
however i am getting an error.
from VSCode this is what I see on terminal when I run the script;
Loading personal and system profiles took 712ms
(base) PS C:\Users\tableauautomation\Desktop\Python> & 'C:\Users\tableauautomation\Anaconda3\python.exe' 'c:\Users\tableauautomation\.vscode\extensions\ms-python.python-2020.7.96456\pythonFiles\lib\python\debugpy\launcher' '64388' '--' 'c:\Users\tableauautomation\Desktop\Python\ForecastAutomation.py'
job Started: 2020-07-26 18:13:30
i am creating this in Notepad saved as bat but keep getting errors like Numpy or Panda's is not installed.
batchfile has this;
call activate my_env
"c:\Users\tableauautomation\Desktop\Python\ForecastAutomation.py"
pause
write the below lines in your notepad with .bat format.
call activate [my_env]
python c:\Users\tableauautomation\Desktop\Python\ForecastAutomation.py
call conda deactivate
if absolute path of python is not included in $PATH then use absoulte path of python.exe in .bat file.
call activate [my_env]
c:\Users\tableauautomation\Anaconda3\python.exe c:\Users\tableauautomation\Desktop\Python\ForecastAutomation.py
call conda deactivate
Anyone else have this issue the solution is here;
The batchfile needs the following parameter (Windows Machine)
cmd /c C:\Users\tableauautomation\Anaconda3\condabin\conda.bat run "C:\Users\tableauautomation\Anaconda3\python.exe" "c:\Users\tableauautomation\Desktop\Python\ForecastAutomation.py"
pause

How to run virtual environment from shell script?

I am trying to setup my project environment from a shell script on ubuntu so that I can skip basic setup every time.
I use my virtual environmet cv using the command workon cv.
But I am having trouble doing so using a shell script. I tried the the script
#!/bin/bash
workon cv
But I get the error
workon: command not found
I try to list all the venv I have
pran#pran-HP-65-Notebook-PC:~$ lsvirtualenv
cv
==
virtual-py2
===========
Also, I thought of locating it
(cv) pran#pran-HP-65-Notebook-PC:~/.virtualenvs$ l
cv/ postdeactivate preactivate* prermvirtualenv*
get_env_details* postmkproject* predeactivate virtual-py2/
initialize postmkvirtualenv premkproject*
postactivate postrmvirtualenv* premkvirtualenv*
How can I do it?
You cannot execute workon command outside of Python virtual environment.
If you are interested, check out this article that will walk you through all of the steps required to set up your virutal env.
If it is not what you need then please clarify your requirements for a project environment.
I found the solution:
My venv was located in .virtualenvs. So, I put the command in the bash file start.sh (meant to be executed before working on my project).
#start.sh
source ~/.virtualenvs/cv/bin/activate
And run it using
$ source start.sh
It works perfectly 👍

Running two shell commands using Python 3.6 on Ubuntu 18.02

In order to get some software running I need to 1. Run a script that will execute a remote license manage, 2. Execute a shell script to start the software. I can do this by opening a command window in the directory with the rlm , and then type ./rlm to run the Linux executable. Then I can go into the directory that contains the shell script, open a terminal in that location and run ./myshell.sh. This opens the GUI for my software.
I would like to run these steps using a single Python script. I have tried:
#change the working directory...
os.chdir(r'/opt/mysoftwarelocation')
#confirm location change...
print(os.getcwd() )
#run ./rlm...
os.system('./rlm')
At this point I can see from a python terminal that the rlm is running.
I would then like to run the code below to run the shell script...
os.chdir(r'/opt/mysoftwarelocation/sumsubdirectory')
print(os.getcwd() )
os.system('./some.sh')
Unfortunately, after os.system('./rlm') finishes the script stalls and will not execute further and without an errors.
How to I get the second part of my script to run within a single Python script?
Have you tried to run the rlm command in the background?
subprocess module gives a nice interface for that

How can I suppress “Terminate batch job (Y/N)” confirmation in PowerShell?

When I press Ctrl+C in PowerShell, I receive:
Terminate batch job (Y/N)?
Similar to https://superuser.com/questions/35698/how-to-supress-terminate-batch-job-y-n-confirmation, except for Windows PowerShell.
Does PowerShell provide any more control over batch jobs than what CMD does?
The behavior is neither caused by PowerShell nor can PowerShell change it (as evidenced by the PowerShell source-code repo not containing the prompt message).
The behavior is built into cmd.exe - Powershell, in this case, is calling a .cmd file (batch file), which is interpreted by cmd.exe.
If you explicitly control the invocation of the target executable, you can fix this by moving to Powershell - note this has its own considerations, see below.
If you do not explicitly control the invocation of the target executable, you're out of luck (unless you're willing to install third-party cmd.exe replacements) and must press Ctrl+C twice in order to terminate execution.
A[n ill-advised] workaround is to modify the cmd.exe binary - see article with instructions on how to patch the cmd.exe executable in order to suppress the prompt. Additionally, you can post a feature request on GitHub to request that this behavior be fixed at the source, though that is unlikely to happen for reasons of backward compatbility.
To demonstrate the behavior:
The examples assume that Node.js is installed and that node.exe is therefore in your PATH:
First, invoke node.exe directly, with a tight loop that requires you to press Ctrl+C to terminate the process.
PS> node -e "while (true);"
As you'll see, pressing Ctrl+C instantly terminates the process - no confirmation prompt.
Now, let's create a sample batch file that invokes the same command and invoke that batch file:
PS> "#echo off`nnode -e `"while (true);`"" | Set-Content test.cmd
PS> ./test.cmd
As you'll see, pressing Ctrl+C now presents the undesired Terminate batch job (Y/N)? prompt. (You'd get the same behavior if you ran the batch file from cmd.exe.)
To demonstrate that gulp is a cmd file:
You say you're running your command via gulp's CLI.
On Windows, the entry point for the gulp CLI is gulp.cmd [see update in the bottom section] - i.e., a batch file. That is how it works in general for npm-package "binaries" (executables) implemented as either JS files or shell scripts.
That gulp invokes gulp.cmd can be verified as follows:
# Execute from a project folder that has `gulp` installed as a dependency.
# If `gulp` is installed *globally*
# Note: CLI `npx` requires npm version 5.2.0+
PS C:\some\NodeJs\project> npx where gulp
You'll see something like:
C:\some\NodeJs\project\node_modules\.bin\gulp
C:\some\NodeJs\project\node_modules\.bin\gulp.cmd
Note that where.exe also lists the extension-less Unix-shell script, ...\gulp; however, from cmd.exe / Powershell such a shell script isn't directly executable, and it is ...\gulp.cmd - the batch file - that is executed.
(If in doubt, place a command such as #set /p dummy="Press a key" at the start of the gulp.cmd file, and you'll see that this command executes when you invoke gulp without the .cmd extension.
Also note that there is no gulp.exe.)
More generally, on Windows, a project's node_modules\.bin subfolder contains pairs of CLI entry points for the CLIs that come with packages that the project depends on locally:
node_modules\.bin\<some-cli> is the Unix shell script (whose executing interpreter is controlled via its shebang line).
node_modules\.bin\<some-cli>.cmd is the helper batch file for Windows.
Updates and future considerations:
In the context of npm modules, the problem would go away if a PowerShell script (*.ps1) were used as the helper script on Windows. There are tickets for npm, yarn and similar software to do this. There are also some drawbacks:
*.ps1 files aren't directly executable from outside of PowerShell, notably from cmd.exe and File Explorer (and changing that is nontrivial).
PowerShell still hasn't fully replaced cmd.exe as the default shell, as of Windows 10 (and won't anytime soon, if ever).
When called from PowerShell, a *.ps1 file would be found and run in-process, so a possible solution is for the npm project to also provide *.ps1 helper scripts, which would take precedence over *.cmd files of the same name.
Update:
Recent versions of npm (verified in 6.14.10) indeed DO install such *.ps1 files.
Alternative package manager yarn, since v2 does not seem to use batch files anymore at all, so the original problem is bypassed there; (v1, by contrast, still uses batch files (only); upgrading from v1 must be done on a per-project basis see the migration instructions).
As the other answer notes, the correct fix is to replace cmd scripts with ps1 versions.
However another workaround for users of the Hyper shell is 'Hyper yes', a plugin that automatically hits y for you when the prompt comes up.
best way to avoid it is to not start it, in my case, is not to type npm run devStart but instead type nodemon ./server.js localhost 3000
here's how it looks like
#echo off
start /w "" "C:\myfile.bat" 2>nul|findstr /i "termin"
if errorlevel 1 goto bypass
:bypass
echo hello by stexup YouTube channel!
timeout /t 5 >nul

Resources