Reputation: 318
Path example: C:\Users\user\Some Space\dev\sensor\
def readSensorList():
with open('sensor.json') as json_data:
data = json.load(json_data)
json_data.close()
return data
def executeSensor():
sensorList = list()
sensorListRaw = readSensorList()
for sensor in sensorListRaw['sensors']:
x = [subprocess.Popen(['powershell.exe','-ExecutionPolicy', 'Unrestricted', sensorListRaw["path"] + sensor["filename"], "-name", sensor["name"]], stdout=subprocess.PIPE, stderr=subprocess.PIPE), sensor["name"]]
sensorList.append(x)
return sensorList
Json containing the path:
{
"path": "C:\\Users\\\\sensor\\",
"sensors":
[{
"name": "partition",
"filename": "partition.ps1"
}]
}
In my test environnement there were no space in the path, but now, in the production, I have some space in the path, and I'm clueless about how to execute powershell script from python with space and parameters
I tried to quote the path, without any success.
Edit: I'm sure the problem come from the powershell.exe command and not from python, because:
powershell.exe -ExecutionPolicy 'Unrestricted C:\Users\some space\Desktop\PythonSensor\sensor\sensor.ps1'
Don't work in the CMD.
Upvotes: 4
Views: 6415
Reputation: 1905
Although process parameters/arguments are indeed handled somewhat inconsistent on Windows, this is not the problem in this case. Pythons submodule.Popen
handles this correctly (based on these rules). (Serge Ballestas example of calling .bat
files does not really fit, because .bat
files are executed by cmd.exe
and cmd.exe
is almost the only application these days that doesn't follow these rules.)
The problem in this case, is the usage of -Command
:
When PowerShell is called with the -Command
parameter, all following arguments are joined to a single command (like $args -join " "
). This command is then executed.
-Command
is the default parameter: If a Parameter does not start with -
or /
, powershell behaves, as if -Command
were present before.
This:
subprocess.Popen(['powershell.exe', r'C:\Users\user\Some Space\dev\sensor\partition.ps1', "-name", "partition"])
is therefore equivalent to this command in an interactive powershell session:
C:\Users\user\Some Space\dev\sensor\partition.ps1 -name partition
If you surround each space with quotes (as described in your own answer), the resulting powershell command is:
C:\Users\user\Some' 'Space\dev\sensor\partition.ps1 -name partition
This is allowed and works - but if your path contains other special characters like $
or `
it will break again. It will also break if the
script argument contains spaces or other special characters.
tl;dr:
To correctly call a powershell script from outside of powershell, use -File
parameter:
subprocess.Popen(['powershell.exe','-ExecutionPolicy', 'Unrestricted', '-File', sensorListRaw["path"] + sensor["filename"], "-name:", sensor["name"]])
The parameter after -File
is the script name (without any additional strange escaping), all following parameters are arguments to the script.
Notice the :
appended to the parameter name (-name:
instead of -name
) - in most cases it will also work without the :
, but if the corresponding value starts with a dash, it will fail without :
.
Upvotes: 2
Reputation: 318
I finally found, you have to put ' between space like this:
powershell -command "C:\Users\me\Desktop\test\ps' 'test.ps1"
In python:
subprocess.Popen(['powershell','-ExecutionPolicy', 'Unrestricted', '-command', path]
with path as:
C:\Users\me\Desktop\some' 'space\sensor\
without " as Serge Ballesta explain.
Upvotes: 5
Reputation: 149185
The problem is not only with Python but also with Windows. Internally Unix-like system use an execve
system call that takes as parameters the (path to) executable file and the arguments that will be passed to the command.
In Windows the system API has the function CreateProcess
that takes as arguments the path to the executable file and the whole command line as a single string. It is then up to the child process to parse the command line to find its parameters
Python does its best to follow Windows internal usages to build a command line that will be parsed as expected, but it fails as soon as one parameter contains double quotes ("
).
For example, if foo.bat
is a batch script taking 3 parameters, this will be correct:
proc = subprocess.Popen(('foo.bat', 'a', 'b c', 'd'),
stdout= subprocess.PIPE, stderr=subprocess.PIPE)
foo will receive 3 parameters, a
, b c
and d
.
But if you use:
proc = subprocess.Popen(('foo.bat', '"a"', '"b c"', '"d"'),
stdout= subprocess.PIPE, stderr=subprocess.PIPE)
foo will receive 4 parameters: "a"
, "b
, c"
and "d"
.
TL/DR: you must ensure that the string that contains a parameter that contains a space is not enclosed in "
Upvotes: 3