Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么';这是从Python执行PowerShell脚本的最佳方式_Python_Python 2.7_Powershell - Fatal编程技术网

什么';这是从Python执行PowerShell脚本的最佳方式

什么';这是从Python执行PowerShell脚本的最佳方式,python,python-2.7,powershell,Python,Python 2.7,Powershell,之前关于这个主题的所有文章都针对它们的用例处理特定的挑战。我认为如果有一篇文章只讨论从Python运行PowerShell脚本的最干净的方法,并询问是否有人有比我发现的更好的解决方案,那将是非常有用的 对于尝试以不同的方式解释命令中的不同控制字符的PowerShell,人们普遍接受的解决方案似乎是使用以下文件为PowerShell命令提供信息: ps = 'powershell.exe -noprofile' pscommand = 'Invoke-Command -ComputerName s

之前关于这个主题的所有文章都针对它们的用例处理特定的挑战。我认为如果有一篇文章只讨论从Python运行PowerShell脚本的最干净的方法,并询问是否有人有比我发现的更好的解决方案,那将是非常有用的

对于尝试以不同的方式解释命令中的不同控制字符的PowerShell,人们普遍接受的解决方案似乎是使用以下文件为PowerShell命令提供信息:

ps = 'powershell.exe -noprofile'
pscommand = 'Invoke-Command -ComputerName serverx -ScriptBlock {cmd.exe \
/c "dir /b C:\}'
psfile = open(pscmdfile.ps1, 'w')
psfile.write(pscommand)
psfile.close()
full_command_string = ps + ' pscmdfile.ps1'
process = subprocess.Popen(full_command_string , shell=True, \
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
当python代码需要在每次调用Powershell命令时更改该命令的参数时,您最终会编写和删除大量临时文件以供subprocess.Popen运行。它工作得很好,但没有必要,也不是很干净。很高兴能够整理一下,并希望就我找到的解决方案的任何改进获得建议

使用io模块创建虚拟文件,而不是将包含PS命令的文件写入磁盘。假设“日期”和“服务器”字符串作为包含此代码的循环或函数的一部分输入,当然不包括导入:

import subprocess
import io
from string import Template
raw_shellcmd = 'powershell.exe -noprofile '
--填充服务器和日期变量的循环开始--


--循环结束--

可以说,最好的方法是使用
powershell.exe-Command
而不是将powershell命令写入文件:

pscommand = 'Invoke-Command ...'
process = subprocess.Popen(['powershell.exe', '-NoProfile', '-Command', '"&{' + pscommand + '}"'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
确保
pscommand
字符串中的双引号已正确转义

请注意,
shell=True
仅在某些边缘情况下是必需的,不应在您的场景中使用。从:

在具有
shell=True
的Windows上,
COMSPEC
环境变量指定默认shell。在Windows上指定
shell=True
的唯一时间是希望执行的命令内置到shell中时(例如dircopy)。运行批处理文件或基于控制台的可执行文件不需要
shell=True


在花了相当多的时间之后

我认为从python运行powershell命令对很多人来说可能没有意义,特别是那些只在windows环境中工作的人。与powershell相比,python有许多明显的优势,因此能够用python执行所有业务逻辑,然后在远程服务器上有选择地执行powershell确实是一件很棒的事情

我现在已经完成了我的“winrmcntl”模块的几项改进,由于公司政策的原因,我无法分享这些改进,但不幸的是,这是我给任何想做类似事情的人的建议。如果直接在目标框的PS中键入,则模块应将未修改的PS命令或scriptblock作为输入。一些技巧:

  • 为避免权限问题,请确保运行python脚本的用户,以及通过process.Popen运行powershell.exe的用户,是对调用命令所指向的windows框具有正确权限的用户。我们使用一个企业调度器,它将windows虚拟机作为python代码所在的代理,负责处理这些问题
  • 你有时会很少,但仍然会从powershell land得到奇怪的、深奥的异常,如果它们与我在奇怪的时候看到的异常类似,microsoft会稍微搔搔头,让你做耗时的应用程序堆栈跟踪。这不仅耗费时间,而且很难做到正确,因为它占用大量资源,而且您不知道下次什么时候会发生异常。在我看来,如果某个文本出现在异常中,解析异常的输出并重试x次会更好、更容易。我在winrmcntl模块中保留一个字符串列表,该模块当前包含一个字符串
  • 如果您不想在powershell命令遍历python->windows->powershell->powershell堆栈时对其进行“按摩”,使其在目标框上按预期工作,我发现的最一致的方法是将一行程序和脚本块写入一个ps_buffer.ps1文件,然后将该文件馈送到源框上的powershell,这样每个process.popen看起来都完全相同,但ps_buffer.ps1的内容会随着每次执行而变化

    powershell.exe ps\u buffer.ps1

  • 为了保持python代码整洁,最好将powershell one行程序列表保存在json文件或类似文件中,并将指向要运行的脚本块的指针保存到静态文件中。您将json文件作为一个有序的dict加载,并根据所做的操作循环发出命令

  • 无论如何强调都不过分,尽可能使用最新稳定版本的PS,但除此之外,必须在客户端和服务器上使用相同的版本
“scriptblock”和“server”是提供给此模块或函数的值

import subprocess
from string import Template

scriptblock = 'Get-ChildItem' #or a PS scriptblock as elaborate as you need   
server = 'serverx'

psbufferfile = os.path.join(tempdir, 'pscmdbufferfile_{}.ps1'.format(server))
fullshellcmd = 'powershell.exe {}'.format(psbufferfile)

raw_pscommad = 'Invoke-Command -ComputerName $server -ScriptBlock {$scriptblock}'
pscmd_template = Template(raw_pscommand)
pscmd = pscmd_template.substitute(server=server, scriptblock=scriptblock)

try:
    with open(psbufferfile, 'w') as psbf:
    psbf.writelines(pscmd)
....

try:
    process = subprocess.Popen(fullshellcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()
....        

这是可行的,我只需要将pscommand设置为一个字符串,其中包含要放入subprocess.Popen的完整命令。正如我得到一个模糊的PS相关错误。process=subprocess.Popen(pscommand,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
import subprocess
from string import Template

scriptblock = 'Get-ChildItem' #or a PS scriptblock as elaborate as you need   
server = 'serverx'

psbufferfile = os.path.join(tempdir, 'pscmdbufferfile_{}.ps1'.format(server))
fullshellcmd = 'powershell.exe {}'.format(psbufferfile)

raw_pscommad = 'Invoke-Command -ComputerName $server -ScriptBlock {$scriptblock}'
pscmd_template = Template(raw_pscommand)
pscmd = pscmd_template.substitute(server=server, scriptblock=scriptblock)

try:
    with open(psbufferfile, 'w') as psbf:
    psbf.writelines(pscmd)
....

try:
    process = subprocess.Popen(fullshellcmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, error = process.communicate()
....