Python запустить команду powershell

What’s the best way to execute PowerShell scripts from Python

All the previous posts on this topic deal with specific challenges for their use case. I thought it would be useful to have a post only dealing with the cleanest way to run PowerShell scripts from Python and ask if anyone has an better solution than what I found. What seems to be the generally accepted solution to get around PowerShell trying to interpret different control characters in your command differently to what’s intended is to feed your Powershell command in using a file:

ps = 'powershell.exe -noprofile' pscommand = 'Invoke-Command -ComputerName serverx -ScriptBlock ' 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) 

When your python code needs to change the parameters for the Powershell command each time you invoke it you end up writing and deleting a lot of temporary files for subprocess.Popen to run. It works perfectly but it’s unnecessary and not very clean. It’s really nice to be able to tidy up and wanted to get suggestions on any improvements I could make to the solution I found. Instead of writing a file to disk containing the PS command create a virtual file using the io module. Assuming that the «date» and «server» strings are being fed in as part of a loop or function that contains this code, not including the imports of course:

import subprocess import io from string import Template raw_shellcmd = 'powershell.exe -noprofile ' 
raw_pslistcmd = r'Invoke-Command -ComputerName $server -ScriptBlock ' \ r'' pslistcmd_template = Template(raw_pslistcmd) pslistcmd = pslistcmd_template.substitute(server=server, date=date) virtualfilepslistcommand = io.BytesIO(pslistcmd) shellcmd = raw_shellcmd + virtualfilepslistcommand.read() process = subprocess.Popen(shellcmd, shell=True, stdout=subprocess.PIPE, \ stderr=subprocess.PIPE) 

2 Answers 2

Arguably the best approach is to use powershell.exe -Command rather than writing the PowerShell command to a file:

pscommand = 'Invoke-Command . ' process = subprocess.Popen(['powershell.exe', '-NoProfile', '-Command', '"&"'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

Make sure double quotes in the pscommand string are properly escaped.

Note that shell=True is required only in certain edge cases, and should not be used in your scenario. From the documentation:

On Windows with shell=True , the COMSPEC environment variable specifies the default shell. The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (e.g. dir or copy). You do not need shell=True to run a batch file or console-based executable.

this works, I just had to make pscommand a string containing the full command to put into subprocess.Popen. As is I got an obscure PS related error. process = subprocess.Popen(pscommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

Er, ‘-Command’, ‘»&<' + pscommand + '>«‘ prints the & <. >string instead of executing it. What seems to work is ‘&<' + pscommand + '>‘ without any escaping. ( & being the call operator and <. >a script block).

Читайте также:  Parse url server request uri php url path

After spending a fair amount of time on this.

I think that running powershell commands from python may not make sense to a lot of people, especially people who work exclusively in windows environments. There are numerous clear advantages to python over powershell however so the ability to do all your business logic in python and then selectively execute powershell on remote servers is truly a great thing.

I’ve now been through several improvements of my «winrmcntl» module which I can’t share due to company policy unfortunately but here is my advice to anyone who would like to do something similar. The module should take as input an unmodified PS command or scriptblock as you’d run it if you were typing directly in PS on the destination box. A few tricks:

  • To avoid permission difficulties, ensure the user running your python script and hence the one running powershell.exe via process.Popen is the user that has the correct permissions on the windows box you’re invoke-command is pointing at. We use an enterprise scheduler which has windows vms as agents on which the python code lives which takes care of that.
  • You will sometimes rarely but still get the odd esoteric exception from powershell land, if they’re anything like the one in particular I saw the odd time, microsoft scratch their heads at a little and get you to do time consuming application stack tracing. This is not only time consuming but very difficult to get right because it’s resource intensive and you don’t know when the exception will next occur. In my opinion, it’s much better and easier to parse the output of the exception and retry up to x number of times if a certain text appears in those exceptions. I keep a list of strings in my winrmcntl module which currently contains a single string.
  • If you want to not have to «massage» the powershell commands as they traverse the python -> windows -> powershell -> powershell stack to make them work as expected on destination boxes, the most consistent method I’ve found is to write your one liners and scriptblocks alike into a ps_buffer.ps1 file which you then feed to powershell on the source box so that every process.popen looks exactly the same but the content of ps_buffer.ps1 changes with each execution. powershell.exe ps_buffer.ps1
  • To keep your python code nice and clean, it’s great having your list of powershell one liners in a json file or similar as well as pointers to scriptblocks you want to run saved into static files. You load up your json file as an ordered dict and cycle through issuing commands based on what you’re doing.
  • Can’t be overstated, as far as is possible try to be on the latest stable version of PS but more than that, it’s imperative to be on the same version on client and server.
Читайте также:  For лун value in python

«scriptblock» and «server» are the values fed to this module or function

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 ' 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() . 

Источник

Run PowerShell function from Python script

I have a need to run a PowerShell function from a Python script. Both the .ps1 and the .py files currently live in the same directory. The functions I want to call are in the PowerShell script. Most answers I’ve seen are for running entire PowerShell scripts from Python. In this case, I’m trying to run an individual function within a PowerShell script from a Python script. Here is the sample PowerShell script:

# sample PowerShell Function hello < Write-Host "Hi from the hello function : )" >Function bye < Write-Host "Goodbye" >Write-Host "PowerShell sample says hello." 
import argparse import subprocess as sp parser = argparse.ArgumentParser(description='Sample call to PowerShell function from Python') parser.add_argument('--functionToCall', metavar='-f', default='hello', help='Specify function to run') args = parser.parse_args() psResult = sp.Popen([r'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe', '-ExecutionPolicy', 'Unrestricted', '. ./samplePowerShell', args.functionToCall], stdout = sp.PIPE, stderr = sp.PIPE) output, error = psResult.communicate() rc = psResult.returncode print "Return code given to Python script is: " + str(rc) print "\n\nstdout:\n\n" + str(output) print "\n\nstderr: " + str(error) 

So, somehow, I want to run the ‘hello()’ or the ‘bye()’ function that is in the PowerShell sample. It would also be nice to know how to pass in parameters to the function. Thanks!

Источник

How to Run PowerShell from Python

In this article we will look at how you can run PowerShell scripts from your python scripts.

I recently had to run a PowerShell script from my own python script and found some interesting information online on how to solve the problem.

In order to enforce the learnings when I do something new I like to write about it, so in this guide we will go through some examples similar to my own use case, and also some other examples just to highlight what is possible.

Problem#

Sometimes you might like to run PowerShell scripts from your python scripts, why? There are a multitude of reasons but the most likely is perhaps you can’t or don’t want to use a python library which could access information you would like, for example system information on windows.

You know you can solve this with PowerShell so if you can call PowerShell scripts from your python code, this will do what you need.

Читайте также:  What is initialcontext in java

Solution#

The key to all this is the python subprocess . This module replaces os.system and os.spawn* here is what the docs have to say about it:

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.

You can check out the documentation for further information, but below are some example use cases to get you started.

Example 1: Running PowerShell from Python to Obtain Operating System Information#

In this example, we are using the python subprocess module and the built in PowerShell Get-ComputerInfo cmdlet which was introduce in PowerShell 5.1.

This simple example will grab the name of your operating system, and then as shown we can take that result and use it in our python code.

In this example, we just print the name of the operating system, but you can see how you could simply do whatever you want with the results from the command.

import subprocess; process=subprocess.Popen(["powershell","Get-ComputerInfo | select -ExpandProperty OsName"],stdout=subprocess.PIPE); result=process.communicate()[0] print ("Our current operating system is:- "+result.decode('utf-8')) > Output:- Our current operating system is:- Microsoft Windows 11 Home 

Example 2: Spawning applications from python#

As you can see in this example, we can spawn any application from python using subprocess Popen that we could run from PowerShell.

So, here are 2 common examples that we like to use, opening notepad and opening calculator from python using PowerShell.

import subprocess; process=subprocess.Popen(["powershell","calc.exe"]); result=process.communicate()[0] print (result) import subprocess; process=subprocess.Popen(["powershell","notepad.exe"]); result=process.communicate()[0] print (result) 

So it’s pretty obvious when you read the PowerShell command what each of these examples is doing. The first one would run the windows calculator program, and the second runs windows notepad.

If the program opens, there is no output, but if it did fail to open then you would get the PowerShell output of the issue.

Conclusion#

On the surface of it, this information might not seem that significant, but in reality, depending what you do with it, it could be very powerful.

Imagine all the things you can do from PowerShell and then being able to wrap that in python maybe with a web front end? One possible example which is pretty exciting would be to create a web gui with some variables that let me deploy sql server installations using PowerShell.

There are also many popular PowerShell modules you could call from python like dbatools. Using other PowerShell modules would really extend the usefulness of being able to call PowerShell scripts from python.

Источник

Оцените статью