Subprocess.Popen() : hide the cmd shell - python

I am trying to call an executable at startup, which will call another executable itself. For the first part, I simply added the path to the executable to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run, which works, my executable is called at startup.
The latter contains, among others, these lines :
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE
proc = subprocess.Popen(command, startupinfo=startupinfo)
However, a command shell (cmd) pops when the computer starts. Everything works fine, but it is visible instead of hidden... So basically, how do I hide this command shell ?
When using ProcessExplorer, I have the following hierarchy :
+ System
|_ Interrupts
|_ smss.exe
|_ some processes...
+ explorer.exe
|_ some processes...
|_ MYSCRIPT.EXE
Here is the sequence I try to achieve :
I create an ISO file containing all the Python executable I want to run on the VM. One of them (master.exe) calls the others.
I create a VM which automatically mount the latter
The VM, which was prepared, has a scheduled task which calls D:\master.exe
master.exe (among other tasks which are not our concern here) adds the value D:\myscript.exe to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
The VM reboots
D:\myscript.exe is run (and it works fine and as attended), but it does run in a command prompt, which I would like to be invisible.

This is a typical problem Python-programmers encounter - and therefore, a solution is offered by Python itself. It has been asked on SO many times, e.g., here, but for you, the problem is a little more complicated.
It's all about whether you use python.exe or pythonw.exe to run your script. For the first one, a console is opened, for the second it's not.
As you use compiled scripts, you have to tell "the compiler" which version you want to use. Assuming you are using py2exe, you can have a look at this post on SO. Here it is explained in detail how to proceed.

The console window that is being opened probably belongs to the Python process running your script. Show us the entry in the registry running your script.

If you run a console program, Windows will create a console window. "python.exe" is a console program.
If you don't want a console window, you can run your Python script with "pythonw.exe" rather than "python.exe".

You can compile it to exe format. When I encounter that problem,
I used py2exe to compile python file to invisible executible.
All you have to do, is to change setup.py file(used to compile), from
setup(console=['__main__.py'], options={"py2exe":{"includes":["sip"]}})
to
setup(windows=['__main__.py'], options={"py2exe":{"includes":["sip"]}})

I had the same issue and I used Pyinstaller.
Pyinstaller is a smart cross platform tool to compile .py file into standalone executable.
Install it via:
pip install pyinstaller (more information here)
Use the following command to hide the console (to make your script a process):
pyinstaller yourfilename.py -F --windowed
(with "-F" flag you'll get a single .exe file and with "--windowed" flag the console will be hidden)

Related

How to run python code from powershell with no command prompt showing?

I would like to be able to run a python script from a .ps1 file without the terminal window showing up to run the script. I would think that there is some extra command I can put at the end to make it run windowless, but I am not sure what it is.
The only code I have in the ps1 file is to execute the python script by linking the path.
I do not want to run the code some way else, it has to be from a ps1 script since I will be adding to it eventually to have more features. I also would rather not have to change the file to a .pyw if possible.
E:/script.py
*Note - I ran the file from a different drive this time, but I want it to be from E:/ like I have in my code.
What I don't want to show up:
In a comment you state:
im using run (WIN + R) and this command: powershell -w h iex (E:\a.ps1)
-w h is short for -WindowStyle Hidden
iex is short for Invoke-Expression, which is not needed here - and should generally be avoided: see this answer.
Note: While this does make the console window that the PowerShell session itself runs in invisible, the window becomes invisible only after briefly showing first.
To avoid this brief flashing of the console window, powershell.exe must be launched indirectly, namely via a GUI-subsystem application that launches it with a hidden window; the bottom section of this answer discusses options.
Also note that supporting this directly in the future is planned, but will likely only be implemented for the CLI of PowerShell (Core) 7+, pwsh.exe - see GitHub issue #3028.
With that out of the way:
Console applications (including .ps1 scripts) invoked directly from a hidden PowerShell session run hidden too, because they run directly in the hidden console window.
By contrast, any GUI applications or applications of either type invoked via Start-Process run visibly.
While you can generally use Start-Process -WindowStyle Hidden to run GUI applications invisibly as well, this, unfortunately, does not seem to work with .pyw files, i.e. pythonw.exe-launched scripts, which still run visibly.[1]
By default, .py files invoked directly execute via py.exe, which is a console application.
Strangely, your screen shot suggests that it is not in your case.
py.exe is normally just a launcher for the true console Python executable (allowing you to switch between v2 and v3 versions of Python with py -2 ... and py -3 ...), python.exe, so as a workaround you can try the following (use a full path to python.exe, if needed):
Modify your E:\a.ps1 script to explicitly invoke your .py script with python.exe:
python.exe E:\script.py
Then launch your invisible PowerShell session as before, except with improved syntax:
# Short for:
# powershell.exe -WindowStyle Hidden -File E:\a.ps1
powershell -w h -f E:\a.ps1
If that doesn't help, consider reinstalling Python.
[1] I'm guessing this is because the windows potentially created by the .pyw scripts themselves are unrelated to the (invisible) main window of the pythonw.exe GUI-subsystem executable.
Start-Process python -ArgumentList "python-script-file-path" -NoNewWindow
Lots of excellent info here.

Pyinstaller "Failed to execute script pyiboot01_bootstrap"

I'm using pyinstaller to produce an exectuable for a python program. But, whenever I try to use a generated executable, I get a message window that reads "Failed to execute script ...".
The command I'm running is pyinstaller -w run.py. But, when run with the --debug option a different error is made apparent. "Failed to execute script pyiboot-1_bootstrap". After this error it kills the program.
I tried with the -F option and that did not change the outcome. All the files I created for the project are in the same directory. I did get warnings that dll's weren't being included but I resolved that.
Pyinstaller doesn't like the built in quit() function I was using.
Instead use sys.exit() to close the program.
See this question to see why sys.exit() is better practice for production code.
What I found useful was to make an exe of my .py script in console mode and then run it. For a very short period of time, I saw an error message in the console window. I had to screenshot it to read completely. So one of the imports was missing from the folder in which I had my script. I opened cmd from the location bar of that folder (by typing cmd there) and imported modules using pip install <module_name>.
Sorry for the long answer, I am a newbie.

Writing a line to CMD in python

I am very new to Python and I have been trying to find a way to write in cmd with python.
I tried os.system and subprocess too. But I am not sure how to use subprocess.
While using os.system(), I got an error saying that the file specified cannot be found.
This is what I am trying to write in cmd os.system('cd '+path+'tesseract '+'a.png out')
I have tried searching Google but still I don't understand how to use subprocess.
EDIT:
It's not a problem with python anymore, I have figured out. Here is my code now.
os.system("cd C:\\Users\\User\\Desktop\\Folder\\data\\")
os.system("tesseract a.png out")
Now it says the file cannot be open. But if I open the cmd separately and write the above code, it successfully creates a file in the folder\data.
Each call to os.system is a separate instance of the shell. The cd you issued only had effect in the first instance of the shell. The second call to os.system was a new shell instance that started in the Python program's current working directory, which was not affected by the first cd invocation.
Some ways to do what you want:
1 -- put all the relevant commands in a single bash file and execute that via os.system
2 -- skip the cd call; just invoke your tesseract command using a full path to the file
3 -- change the directory for the Python program as a whole using os.chdir but this is probably not the right way -- your Python program as a whole (especially if running in a web app framework like Django or web2py) may have strong feelings about the current working directory.
The main takeaway is, os.system calls don't change the execution environment of the current Python program. It's equivalent to what would happen if you created a sub-shell at the command line, issued one command then exited. Some commands (like creating files or directories) have permanent effect. Others (like changing directories or setting environment variables) don't.

Running Python from the Windows Command Line

How do I run a Python file from the Windows Command Line (cmd.exe) so that I won't have to re-enter the code each time?
Wouldn't you simply save your Python code into a file, and then execute that file using Python?
Save your code into a file called Test.py.
And then run it?
$ C:\Python24\Python.exe C:\Temp\Test.py
If you don't want to install an IDE, you can also use IDLE which includes a Python editor and a console to test things out, this is part of the standard installation.
If you installed the python.org version, you will see an IDLE (Python GUI) in your start menu. I would recommend adding it to your Quick Launch or your desktop - whatever you are most familiar with. Then right-click on the shortcut you have created and change the "Start in" directory to your project directory or a place you can mess with, not the installation directory which is the default place and probably a bad idea.
When you double-click the shortcut it will launch IDLE, a console in which you can type in Python command and have history, completion, colours and so on. You can also start an editor to create a program file (like mentioned in the other posts). There is even a debugger.
If you saved your application in "test.py", you can start it from the editor itself. Or from the console with execfile("test.py"), import test (if that is a module), or finally from the debugger.
If you put the Python executable (python.exe) on your path, you can invoke your script using python script.py where script.py is the Python file that you want to execute.
Open a command prompt, by pressing Win+R and writing cmd in that , navigate to the script directory , and write : python script.py
A good tool to have is the IPython shell. Not only can it run your program (%run command), but it offers also many tools for using Python interactively in an efficient manner (automatic completion, syntax coloring, quick access to the documentation, good interaction with Matplotlib,…). After you install it, you'll have access to its shell in the Start menu.
You need to create environment variables. Follow the instructions here: http://www.voidspace.org.uk/python/articles/command_line.shtml#environment-variables
In DOS you can use edit to create/modify text files, then execute them by typing python [yourfile]

Changing prompt working directory via Python script

Is it possible to change the Windows command prompt working directory via Python script?
e.g.
>> cd
>> c:\windows\system32
>> make_decision_change_dir.py
>> cd
>> c:\windows
I have tried a few things which don't work:
import os
os.chdir(path)
import os, subprocess
subprocess.Popen("chdir /D \"%s\"" %path, shell=True)
import os, subprocess
subprocess.Popen("cd \"%s\"" %path, shell=True)
import os, subprocess
subprocess.Popen("CD=\"%s\"" %path, shell=True)
As I understand it and observe these operations change the current processes working directory - which is the Python process and not the prompt its executing from.
Thanks.
UPDATE
The path I would want to change to is dynamic (based on what project I am working on, the full path to a build location changes) hence I wanted to code a solution in Python rather than hack around with a Windows batch file.
UPDATE
I ended up hacking a batch file together to do this ;(
Thanks everyone.
I'm not clear what you want to do here. Do you want a python script which you can run from a Windows command prompt which will change the working directory of the Windows command session?
If so, I'm 99.9% sure that's impossible. As you said yourself the python.exe process is a separate process from the Windows cmd.exe and anything you do in Python won't affect the Command prompt.
There may be something you can do via the Windows API by sending keystrokes to the Windows or something but it would be pretty brittle.
The only two practical options I can think of involve wrapping your Python script in a Batch file:
Output your desired directory from the Python script, read the output in your Batch file and CD to it.
Start your Python script from a batch file, allow your Python script to start a new cmd.exe Window and get the Batch file to close the original Command window.
I have a Python script to make moving around a file tree easier: xdir.py
Briefly, I have an xdir.py file, which writes Windows commands to stdout:
# Obviously, this should be more interesting..
import sys
print "cd", sys.argv[1]
Then an xdir.cmd file:
#echo off
python xdir.py %* >%TEMP%\__xdir.cmd
call %TEMP%\__xdir.cmd
Then I create a doskey alias:
doskey x=xdir.cmd $*
The end result is that I can type
$ x subdir
and change into subdir.
The script I linked to above does much more, including remembering history, maintaining a stack of directories, accepting shorthand for directories, and so on.
One common solution is a two-part script.
Part 1 is Python, which creates a temporary .BAT file that contains the appropriate CD command.
Part 2 is the temporary .BAT file.
fancycd.bat
python figurethepath.py >temp.bat
temp.bat
As people mentioned, child processes (i.e. your program) can't change the current working directory of a parent process (i.e. the terminal). This is why you need the two steps that everybody is describing. In most shells there's a way to make a macro or function to perform this two-step functionality.
For example, in bash, you can make a single alias to compute the path and change the current working directory, similar to what #S.Lott describes for Windows:
alias my_cd='TMP=`compute_path.py`; cd $TMP;'
Note that the cd command is still being interpreted in the parent process (the terminal), which has the ability to change its own current working directory.
The subprocess.Popen() doc page says a child process will be created for the sub-process, so any working directory changes will be local to that subprocess.
If cwd is not None, the child’s current directory will be changed to cwd before it is executed. Note that this directory is not considered when searching the executable, so you can’t specify the program’s path relative to cwd.
This will be the same for any changes done explicitly inside the subproceess, similar to the commands that appear in the question.
imoprt os
os.system("start cmd.exe /k \"cd /d c:\\windows\\system32 & python make_decision_change_dir.py\"")

Categories