Summary: Microsoft MVP, David O’Brien, talks about using the pywinrm module to execute Windows PowerShell from Linux.
Microsoft Scripting Guy, Ed Wilson, is here. Today Windows PowerShell MVP, David O’Brien, talks about executing Windows PowerShell on Linux.
Hi. I’m David O’Brien, Microsoft MVP for Windows PowerShell, and I was asked by Ed if I wanted to share some of my knowledge on his blog. Sure, cool idea! If you want to read more from me, head over to my personal blog or follow me on Twitter @david_obrien.
I recently changed jobs. I am now not only managing and implementing the Windows operating system, but I also have to manage Linux machines, mostly through tools like Puppet, or in this case, Ansible. This was very scary in the beginning—everything is so different. All I knew was PowerShell and Windows and I was wondering how I would cope. I did. Microsoft did a great job with PowerShell. It is so similar to all that’s already out there and it made my transition so much easier!
All of the traditional (read older, mature, already present at most companies) configuration management tools were born in the Linux universe—none of them on Windows, except maybe System Center Configuration Manager, but I am not going to get into that.
Why all on Linux? Because it’s easier (document-based configuration management on Linux vs API-based configuration management on Windows). It was also needed more because most huge installations were run on Linux servers that somehow needed to be managed.
This recently changed quite a bit, and the industry found itself in a position where it needed to act. This is why, for example, Chef and Puppet started partnering with Microsoft (or the other way around?). They are now releasing statement after statement and new modules to support Windows. However, they have chosen to install an agent on Windows, which makes executing code a lot easier.
In my current project, I am doing a lot of Ansible coding. They (like the others) support Windows, but without a local agent installed, and I quite like that idea—especially because I can now run PowerShell commands from my MacBook Pro against a remote Windows operating system. This article won’t explain Ansible, but rather how Ansible uses WinRM to execute PowerShell from a non-Windows host.
Of course, I can’t run PowerShell on Linux. However, there is a module available, written in Python, that wraps WinRM calls and executes them for you.
pywinrm is an open-source module hosted on GitHub. It can easily be installed on your Mac or other Linux system by using this command:
pip install pywinrm
In Windows, we only need to make sure that WinRM is enabled:
winrm set winrm/config/client/auth @{Basic="true"}
winrm set winrm/config/service/auth @{Basic="true"}
winrm set winrm/config/service @{AllowUnencrypted="true"}
You can also skip the basic authentication if you’re on a domain and want to use Kerberos protocol instead. If that’s the case, you have to also install some Kerberos packages on your Linux machine:
sudo apt-get install python-dev libkrb5-dev
pip install Kerberos
The stage should now be set, and you can ssh into your Linux host or open a terminal on your MacBook and start working.
There are two ways we can go from here. Either write a Python script and execute that in a Python environment, or use the command line in Python. I will do the latter for demo purposes.
On the command line, I entered a Python environment and first imported the WinRM module. Next I created a winrm.Session object by building the connection string with the HostName parameter and an authentication credential parameter pair. In this case, I am using a Vagrant box with local authentication.
We now have the ability to send commands to this session and get data back via the stdout stream.
Built-in execution methods
The session object in the pywinrm module has two execution methods: run_cmd and run_ps. However, by looking at the actual code of __init__.py , we can see that run_ps is simply calling run_cmd and executing powershell.exe with a base64 encoded command string.
They use a neat little trick here to make it a bit harder to figure out what is being executed via PowerShell—I also suspect to make it a bit more robust. The module encodes the string or PowerShell file into a base64 encoded command and executes that on the remote machine, instead of using a clear text string.
I can now execute the following command to find out which Windows features are installed on that remote machine.
(Get-WindowsFeature).Where{$PSItem.Installed}
That wrapped into the WinRM module, and we get this little output via std_out. It’s not really nicely formatted, but that’s usually not the point.
The point is that I can now also create a folder by applying Desired State Configuration, for example. Test it for yourself:
Invoke-DscResource -Name File -Method Set -Property @{'ensure'='present';'destinationPath'='c:\ScriptingGuys';'Type'='Directory'} -Verbose
I hope that this little exercise explained a bit how a tool like Ansible easily supports both the Linux and Windows worlds. All it needs to know is whether to use the pywinrm module, open a WinRM session, and execute the command in that session. This immensely simplifies managing Windows machines from remote non-Windows operating systems, and it makes integrating the Windows operating system into a heterogeneous configuration management environment a lot easier.
~David
Thanks, David, for this great information about using Windows PowerShell to execute on Linux. Join me tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy