如何从python执行powershell脚本,路径和参数中有空格

时间:2016-05-31 13:47:46

标签: python powershell subprocess

路径示例: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包含路径:

{
                "path": "C:\\Users\\\\sensor\\",
                "sensors": 
                    [{
                        "name": "partition",
                        "filename": "partition.ps1"
                    }]
            }

在我的测试环境中,路径中没有空间,但是现在,在生产中,我在路径中有一些空间,而且我对如何使用空间和参数从python执行powershell脚本毫无头绪

我试着引用这条路,没有任何成功。

编辑:我确定问题来自powershell.exe命令,而不是来自python,因为:

powershell.exe -ExecutionPolicy 'Unrestricted C:\Users\some space\Desktop\PythonSensor\sensor\sensor.ps1'

不要在CMD中工作。

3 个答案:

答案 0 :(得分:2)

问题不仅在于Python,还在于Windows。内部类Unix系统使用execve系统调用,该调用将(路径)可执行文件和将传递给命令的参数作为参数。

在Windows中,系统API具有函数CreateProcess,该函数将可执行文件的路径和整个命令行作为参数作为单个字符串。然后由子进程决定解析命令行以查找其参数

Python尽最大努力遵循Windows内部使用来构建一个将按预期解析的命令行,但只要一个参数包含双引号("),它就会失败。

例如,如果foo.bat是一个带有3个参数的批处理脚本,那么这是正确的:

 proc = subprocess.Popen(('foo.bat', 'a', 'b c', 'd'),
    stdout= subprocess.PIPE, stderr=subprocess.PIPE)

foo将收到3个参数,ab cd

但是如果你使用:

 proc = subprocess.Popen(('foo.bat', '"a"', '"b c"', '"d"'),
    stdout= subprocess.PIPE, stderr=subprocess.PIPE)

foo将收到4个参数:"a""bc""d"

TL / DR:您必须确保包含空格的参数的字符串包含在"

答案 1 :(得分:2)

我终于找到了,你必须把'放在这样的空间之间:

powershell -command "C:\Users\me\Desktop\test\ps' 'test.ps1"

在python中:

subprocess.Popen(['powershell','-ExecutionPolicy', 'Unrestricted', '-command', path]

路径为:

C:\Users\me\Desktop\some' 'space\sensor\ 

没有“正如Serge Ballesta解释的那样。”

答案 2 :(得分:1)

尽管在Windows上确实处理参数/参数有点不一致,但在这种情况下这不是问题。 Pythons submodule.Popen正确处理(基于these rules)。 (Serge Ballesta调用.bat文件的示例并不合适,因为.bat文件由cmd.exe执行而cmd.exe几乎是目前唯一的应用程序不遵循these rules。)

在这种情况下的问题是使用-Command

使用-Command参数调用PowerShell时,所有后续参数都会连接到单个命令(如$args -join " ")。然后执行该命令。

-Command是默认参数:如果参数不以-/开头,则powershell会表现出来,就像之前存在-Command一样。

此:

subprocess.Popen(['powershell.exe', r'C:\Users\user\Some Space\dev\sensor\partition.ps1', "-name", "partition"])
因此,

等同于交互式PowerShell会话中的此命令:

C:\Users\user\Some Space\dev\sensor\partition.ps1 -name partition

如果用引号包围每个空格(如您自己的答案中所述),则生成的powershell命令为:

C:\Users\user\Some' 'Space\dev\sensor\partition.ps1 -name partition

这是允许的并且有效 - 但如果您的路径包含其他特殊字符,例如$`,它将再次中断。它也会破坏 script参数包含空格或其他特殊字符。

<强> TL;博士

要从powershell外部正确调用powershell脚本,请使用-File参数:

subprocess.Popen(['powershell.exe','-ExecutionPolicy', 'Unrestricted', '-File', sensorListRaw["path"] + sensor["filename"], "-name:", sensor["name"]])

-File之后的参数是脚本名称(没有任何其他奇怪的转义),所有以下参数都是脚本的参数。

请注意:附加到参数名称(-name:而不是-name) - 在大多数情况下,它也可以在没有:的情况下工作,但如果相应的值以短划线开头,没有:就会失败。