Skip to content

Instantly share code, notes, and snippets.

@diyan
Created June 1, 2012 09:54
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save diyan/2850866 to your computer and use it in GitHub Desktop.
Save diyan/2850866 to your computer and use it in GitHub Desktop.
Python with PowerShell Remoting (Windows equivalent for Unix ssh sessions)
# Note that target_env.login and target_env.password is global variables
# Maybe I should add this into Fabric project (http://docs.fabfile.org/en/1.4.2/index.html).
# This is complicated task for sure but it would be nice if Fabric could use ssh under Linux and PowerShell Remoting under Windows.
def remote_sh(target_host, command_text, ignore_error=False):
print('run PowerShell script block at {0}: {1}'.format(target_host, command_text))
command_text = command_text.replace('"', '\'')
# -NoProfile -NonInteractive PowerShell parameters decrease execution time
power_shell_text = """\
powershell -NoProfile -NonInteractive
\"$secure_password = ConvertTo-SecureString '{1}' -asPlainText -Force;
$credentials = New-Object Management.Automation.PSCredential('{0}', $secure_password);
$remote_session = New-PSSession -ComputerName {2} -Credential $credentials;
Invoke-Command -Session $remote_session -ScriptBlock {{ {3} }};
$remote_last_exit_code = Invoke-Command -Session $remote_session -ScriptBlock {{ $LastExitCode }};
Remove-PSSession -Session $remote_session;
exit $remote_last_exit_code\"""".format(
target_env.login,
target_env.password,
target_host,
command_text)
power_shell_text = dedent(power_shell_text).replace('\n', ' ')
# This print call could be uncommented for debugging purposes
# print('run shell command: {0}'.format(power_shell_text))
error_code = os.system(power_shell_text)
if error_code and not ignore_error:
raise Exception('Failed to execute PowerShell script block on host {0}. Actual return code was {1} '
'but only zero value is expected. '
'Script block is "{2}".'.format(target_host, error_code, command_text))
return error_code
@oddur
Copy link

oddur commented Sep 28, 2012

Any reason why this better than https://gist.github.com/3228308 ?

@diyan
Copy link
Author

diyan commented Dec 12, 2012

To oddur. Sorry for delay with answer.

This gist (https://gist.github.com/2850866) is better than you have mention (https://gist.github.com/3228308) because it uses WinRS command line tool instead of PowerShell Remoting.

Basically we have WinRM protocol and two reference implementation:

  1. WinRS command line tool which can be executed from cmd.exe shell or just as separate process.
  2. PowerShell Remoting is more complicated/powerful but fit better if you are using PowerShell (not Python).

So, in context of Python scripting it would be much easier mix Python with cmd.exe with WinRS.

In case with PowerShell Remoting you have to know both Python and PowerShell.

Also I would like to stress that both cases works only on Windows Vista+ or Windows Server 2008+ :(

I'm planning develop cross-platform library which will execute remote commands via WinRM protocol in pure Python and move away from WinRS tool.

@samyscoub
Copy link

Hi !
I've tested this on my Windows 2008 servers and it works.
Why don't you propose this code into Fabric main project ?

@diyan
Copy link
Author

diyan commented Feb 3, 2013

To samyscoub.

Actually I was thinking about this right after I've implement this functionality and developed monkey patch for Fabric (check https://gist.github.com/3228308) which works with WinRM.

At the very beginning I wanted create cross-platform implementation of WinRM protocol (check https://github.com/diyan/pywinrm) and after that start working on Fabric.

But the more I think about this idea the less I liked it.

Fabric completely tied to ssh protocol implementation. I had to do major changes in it's architecture and change not only transport level implementation but also a lot of places which tied to Bash/Linux environment.

So, I changed my mind on this topic and don't have any plans integrate WinRM transport into Fabric project.

Sorry about that.

FYI, I'm looking now at Ansible project (https://github.com/ansible/ansible) now. It's much more complicated that Fabric for deployment tasks but it have interfaces for integrate WinRM transport.

So, it's really possible integrate pywinrm transport implementation into Ansible without too much effort.

Actually I have some working results on my own workstation but I'm not ready push them into Ansible yet.

I really liked Ansible source codes, their approach on writing modules and functionality (configuration management, ad-hoc task execution and deployment in single(!) product).

At the same time I don't really like Ansible's GPL license but I understand their choice and this is not showstopper for me.

@anandnevase
Copy link

When I am executing same sample code on my machine, script remain in blocking state (i.e. powershell process in back ground never get closed).
Platform i am using is
OS : Windows 7 - 64bit
Python Version : Python 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] on win32

@robertcatgithub
Copy link

This is pretty sweet ! small bite, tastes great !

Does exactly what I need: run remote PS1 script & commands.
I modified os.system() to proc = subprocess.Popen(power_shell_text, stdout=subprocess.PIPE, shell=True)
so I can process the big chunk of return info.

Alexey, did you ever release that library ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment