Executing a PowerShell script OUTSIDE of Python - python

I am trying to run a sort of application that utilises both Python and powershell scripts. I already wrote the Python script and powershell script, which are meant to work simultaneously but separate from each other. What I want to do is create a Python program that launches them both, is there a way? Thanks!
What I have right now, as part of a larger script, is:
import subprocess
autom = r"C:\Users\mrmostacho\Desktop\Robot\Autom.ps1","-ExecutionPolicy","Unrestricted"
powershell = r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
subprocess.Popen("%s %s" % (powershell, autom,))

I think you don't want "-ExecutionPolicy","Unrestricted" as script arguments but instead want to set powershells execution policy to allow the execution of your script. Therefore you should pass those parameters before the actual Script.
Second: It's not enough, to pass the script as argument to powershell.exe (this way the script name is interpreted as Powershell command and one has to escape the name according to powershells quoting rules). Instead the Script name should be given after the -File parameter. From online documentation:
-File []
Runs the specified script in the local scope ("dot-sourced"), so that the functions and variables that the script creates are
available in the current session. Enter the script file path and any
parameters. File must be the last parameter in the command, because
all characters typed after the File parameter name are interpreted as
the script file path followed by the script parameters.
You can include the parameters of a script, and parameter values, in
the value of the File parameter. For example: -File .\Get-Script.ps1 -Domain Central
Typically, the switch parameters of a script are either included or
omitted. For example, the following command uses the All parameter of
the Get-Script.ps1 script file: -File .\Get-Script.ps1 -All
In rare cases, you might need to provide a Boolean value for a switch
parameter. To provide a Boolean value for a switch parameter in the
value of the File parameter, enclose the parameter name and value in
curly braces, such as the following: -File .\Get-Script.ps1 {-All:$False}.
Third: As cdarke already commented, it's better to use a list instead of a string as argument to Popen. This way one doesn't need to worry about the CommandLine parsing on Windows.
Altogether, this should be the way to go. (Tested with small test script.)
import subprocess
autom = r"C:\Users\mrmostacho\Desktop\Robot\Autom.ps1"
powershell = r"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
subprocess.Popen([powershell,"-ExecutionPolicy","Unrestricted","-File", autom])
If you need to pass arguments to the script, do it like this:
subprocess.Popen([powershell,"-ExecutionPolicy","Unrestricted","-File", autom, 'arg 1', 'arg 2'])

Related

Is it possible to run a python script from the windows command prompt and pass an argument for that script at the same time?

I have a saved python script. I run this python script from the command prompt in Windows 10.
This is as simple as navigating to the directory where the script is located and then typing:
python myscript.py
and the script will run fine.
However, sometimes, I want to run this script such that a variable within that script is set to one value and sometimes to another. This variable tells the script which port to operate an API connection through (if this is relevant).
At the moment, I go into the script each time and change the variable to the one that I want and then run the script after that. Is there a way to set the variable at the time of running the script from the command prompt in Windows 10?
Or are there potentially any other efficient solutions to achieve the same flexibility at the time of running?
Thanks
The usual way to do this is with command-line arguments. In fact, passing a port number is, after passing a list of filenames, almost the paradigm case for command-line arguments.
For simple cases, you can handle this in your code with sys.argv
port = int(sys.argv[1])
Or, if you want a default value:
port = int(sys.argv[1]) if len(sys.argv) > 1 else 12345
Then, to run the program:
python myscript.py 54321
For more complicated cases—when you have multiple flags, some with values, etc.—you usually want to use something like argparse. But you'll probably want to read up a bit on typical command-line interfaces, and maybe look at the arguments of tools you commonly, before designing your first one. Because just looking at all of the options in argparse without knowing what you want in advance can be pretty overwhelming.
Another option is to use an environment variable. This is more tedious if you want to change it for each run, but if you want to set it once for an entire series of runs in a command-line session, or even set a computer-wide default, it's a lot easier.
In the code, you'd look in os.environ:
port = int(os.environ.get('MYSCRIPT_PORT', 12345))
And then, to set a port:
MYSCRIPT_PORT=54321
python myscript.py
You can combine the two: use a command-line argument if present, otherwise fall back to the environment variable, otherwise fall back to a default. Or even add a config file and/or (if you only care about Windows) registry setting. Python itself does something like three-step fallback, as do many major servers, but it may be overkill for your simple use case.
You should look at argparse. Heres an example:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-m", help='message to be sent', type=str)
args = (parser.parse_args())
print args.m
Each argument you create is saved like a dictionary so you have to call it in your code like I did with my print statement
"args.m" < ---- This specifies the argument passed you want to do stuff with
here was my input/output:
C:\Users\Vinny\Desktop>python argtest.py -m "Hi"
Hi
C:\Users\Vinny\Desktop>
More info on argparse:https://docs.python.org/3/library/argparse.html
You need the argparse library.
https://docs.python.org/3/library/argparse.html
https://docs.python.org/2/library/argparse.html

Executing a shell script with arguments from a python script

My Shell script is executed like this from the command line
./pro.sh "Argument1"
I am calling it from my python script currently like this
subprocess.call(shlex.split('bash pro.sh "Argument1"'))
How do I pass the value of Argument1 as a variable. My argument to the script can be any string. How do I achieve this?
You can use
subprocess.Popen(["bash", "pro.sh", "Argument1"])
If your string argument is multiple words, it should work fine.
subprocess.Popen(["bash", "pro.sh", "Argument with multiple words"])
As long as the multiple words are in one string in the list passed to subprocess.Popen(), it is considered one argument in the argument list for the command.
You should not use shell=True unless you have a good reason. It can be a security problem if you aren't very careful how it is used.
use subprocess to call your shell script
subprocess.Popen(['run.sh %s %s' % (var1, var2)], shell = True)

Passing variable from bash-python-bash

To use logarithmic function, I used export to pass a variable $var1 from bash to python script. After the calculation, I used
os.environ['var1']=str(result)
to send the result back to bash script.
However, the bash still shows the unmodified value.
You can have a look at the os.putenv(key, value) function here maybe it could help you.
Although as noted on the doc :
When putenv() is supported, assignments to items in os.environ are automatically translated into corresponding calls to putenv(); however, calls to putenv() don’t update os.environ, so it is actually preferable to assign to items of os.environ.
EDIT :
moooeeeep thought about it just a minute before me, but the variable you change only applies to the current process. In such a case I can see two solutions :
- Write the data to a file and read it with your bash script
- Call your bash script directly from within python so that the bash process would inherit your modified variable.

space in python subprocess.Popen() arguments

I try to invoke an external perl script in my python script. I used subprocess.Popen(). If run it like
subprocess.Popen([mybinary, '-arg1 argv1', '-arg2 argv2'])
the arguments are not sent to mybinary. But if I separate arguments from values, then it runs properly:
subprocess.Popen([mybinary, '-arg1', 'argv1', '-arg2', 'argv2'])
Why is it so? args needs to be a string or list. If I concatenate mybinary and the arguments into a single string for Popen(), Popen() does not work, either. I suspect it is relevant to the key-worded arguments (**kwargs). But the script invoked is external. I don't see the reason.
I try to invoke an external perl script in my python script. I used
subprocess.Popen(). If run it like
subprocess.Popen([mybinary, '-arg1 argv1', '-arg2 argv2'])
the arguments are not sent to mybinary.
I doubt that. I rather think they come along there in a non-proper way.
The script expects options and their values as two separate arguments. If they are combined, it doesn't work.
The arguments are passed in shape and count exactly as you give them in the list.

run python command line arguments in shell script

I have a script which takes in few arguments
./hal --runtest=example
where example = /home/user/example.py
how can I pass these arguments in shell script?
I'm having trouble figuring out what you're asking, but assuming your question is "How can a shell script pass dynamic arguments to a command that happens to be written in Python" and you are using a Bourne-family shell (very likely), the simplest correct answer would be
example=/home/user/example.py
./hal "--runtest=$example"
The shell will resolve the quoting and the script will see --runtest=/home/user/example.py without breaking if you later decide to pass in a path containing spaces.
Take a look a the following:
http://lowfatlinux.com/linux-script-variables.html
It is Bash specific though and as per comments above not sure which shell you're using.
Here you'll find all you need in terms of how to pass an argument to a shell script.

Categories