Ansible powershell module to be run on remote powershell on Linux machine.

Has anybody successfully run powershell on Linux as an ansible module? Well, I have an ansible on one machine ServerAnsible. And, I have a powershell and powercli core installed on my linux machine ServerPS. I would like to execute ansible module written in powershell from ansible machine to the powershell machine. I followed the ansible doc here, http://docs.ansible.com/ansible/intro_windows.html#developers-supported-modules-and-how-it-works But it looks like it is specific to Windows or works only when Powershell is on Windows machine.
My end goal is to develop a vmware powercli modules that are delegated through a linux box running powershell and powercli instead of Windows machine.
Here are what I did:
Powershell machine: ServerPS
Ansible machine: ServerAnsible

File mymodule.ps1 at module directory:
#!/usr/bin/powershell
# POWERSHELL_COMMON
# WANT_JSON

$resullt = Get-Date

Exit-Json $result

ServerAnsible$ansible ServerPS -m mymodule.ps1
ServerPS | FAILED! => {
“changed”: false,
“failed”: true,
“module_stderr”: “”,
“module_stdout”: “\u001b[?1h\u001b=\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31mThe variable ‘$result’ cannot be retrieved because it has not been set.\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31mAt /home/******/.ansible/tmp/ansible-tmp-1477059401.24-235352349739057/mymod\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31mules.ps1:233 char:11\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31m+ Exit-Json $result\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31m+ ~~~~~~~\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31m + CategoryInfo : InvalidOperation: (result:String) , RuntimeExc \u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31m eption\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31m + FullyQualifiedErrorId : VariableIsUndefined\u001b[39;49m\u001b[39;49m\r\n\u001b[39;49m\u001b[31m\u001b[39;49m\u001b[31m \u001b[39;49m\u001b[39;49m\r\n”,
“msg”: “MODULE FAILURE”,
“parsed”: false
}

or, if I set the variable as:
#!/usr/bin/powershell

POWERSHELL_COMMON

WANT_JSON

$result=“test”
$resullt = Get-Date

Exit-Json $result

I am getting something like:
ServerPS | FAILED! => {
“changed”: false,
“failed”: true,
“module_stderr”: “”,
“module_stdout”: “\u001b[?1h\u001b="test"\r\n”,
“msg”: “MODULE FAILURE”,
“parsed”: false
}

With verbose mode, looks like ansible is pushing the file to the remote server at least and trying to execute the powershell module.
ESTABLISH SSH CONNECTION FOR USER: *******
SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=******* -o ConnectTimeout=10 -o ControlPath=/home//.ansible/cp/ansible-ssh-%h-%p-%r ServerPS ‘/bin/sh -c ‘"’"’( umask 77 && mkdir -p “echo $HOME/.ansible/tmp/ansible-tmp-1477059699.61-150822866162574” && echo ansible-tmp-1477059699.61-150822866162574=“echo $HOME/.ansible/tmp/ansible-tmp-1477059699.61-150822866162574” ) && sleep 0’“'”‘’
PUT /tmp/tmpGt6Vr_ TO /home/
/.ansible/tmp/ansible-tmp-1477059699.61-150822866162574/mymodules.ps1
SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=******* -o ConnectTimeout=10 -o ControlPath=/home//.ansible/cp/ansible-ssh-%h-%p-%r ‘[ServerPS]’
ESTABLISH SSH CONNECTION FOR USER: *******
SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=
-o ConnectTimeout=10 -o ControlPath=/home//.ansible/cp/ansible-ssh-%h-%p-%r -tt ServerPS '/bin/sh -c ‘"’"'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/powershell /home//.ansible/tmp/ansible-tmp-1477059699.61-150822866162574/mymodules.ps1; rm -rf “/home/*******/.ansible/tmp/ansible-tmp-1477059699.61-150822866162574/” > /dev/null 2>&1 && sleep 0’“'”‘’

Here is the powershell machine where I have a working powershell:
[*******@ServerPS unixVMtool]$ powershell
PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS /home/*******/unixVMtool> $PSVersionTable.PSVersion
Major Minor Patch Label


6 0 0 alpha
PS /home//unixVMtool> Get-Date | ConvertTo-Json
{
“value”: “2016-10-21T07:32:26.261558-07:00”,
“DisplayHint”: 2,
“DateTime”: “Friday, October 21, 2016 7:32:26 AM”
}
PS /home/
/unixVMtool>

Wondering if powershell ansible module can even be run on powershell on Linux ?

Any help on this is appreciated.

Thanks.

The first thing I notice is that ansible requires that modules return JSON, and in your case, you are just returning “test”.

So maybe what you want to try is something like:

#!/usr/bin/powershell

WANT_JSON

POWERSHELL_COMMON

$result = New-Object psobject

Set-Attr $result “msg” “test”
Exit-Json $result

Some aspects of Ansible’s Powershell support are currently built under the assumption that it would only ever run on Windows / over WinRM. There are a few things that would need to be moved around in order to allow “real” Ansible Powershell modules to work on Linux. By “real”, I mean so that the module generation stuff works correctly whether the WinRM connection plugin runs it or something else, and that you can use our Powershell module API.

You can probably make Powershell modules work today by setting the shebang to your powershell path and dealing with the low-level module stuff yourself (or patching powershell.ps1 into the module manually). Now that Powershell for Linux has been released, we’ll take a look at the feasibility of doing this for real, but the likelihood of most existing Ansible Powershell modules working unmodified on Linux seems pretty low.

My intent is to build some other cross-platform modules around Powershell though (for instance, a set of SQL Server modules that could work on either Windows or Linux hosts with .NET Core/Powershell), but that’s probably not going to happen until the 2.4 timeframe.

Good luck!

-Matt

Even with that I got Module failure. It has to do with the ansible parsing different over WinRM and ssh as Matt Davis suggested below.

“module_stdout”: “\u001b[?1h\u001b={"msg":"test"}\r\n”,
“msg”: “MODULE FAILURE”,

Thanks for looking into this though.

Looks like best bet for me now is to simply use Windows Powershell until it is supported from ansible itself. Thank you.

Strange, in any case I did test that module running powershell against my Mac, and it worked fine:

TASK [pstest] ******************************************************************
ok: [localhost] => {“changed”: false, “file”: “/Users/matt/.ansible/tmp/ansible-tmp-1477081774.17-151155167231051/pstest.ps1”, “msg”: “test”}

The only difference is that I also had it output the path of the executing module to show it was a powershell script.

I know I am a bit late to this thread, and I guess it is possible you have a lot of powercli written already, but it might be worth your while investigating the existing vsphere and wmware modules.

Jon

I tested this using Ubuntu shortly after the PowerShell beta for Linux was out, and did not have any problems. Simply put, it should work. Let me know if you’re still blocked by this and I can fire up a test vm tomorrow to verify.

Yes, if this works on Linux host (I am using rhel7) that would be great. Please note that my control server (ansible server) and powershell host are different.
The module as simple as this is not working:

#!/usr/bin/powershell

WANT_JSON

POWERSHELL_COMMON

“some test text” | Out-File /tmp/testfile.txt

Getting following error:

FAILED! => {
“changed”: false,
“failed”: true,
“invocation”: {
“module_name”: “mymodule2.ps1”
},
“module_stderr”: “”,
“module_stdout”: “\u001b[?1h\u001b=”,
“msg”: “MODULE FAILURE”,
“parsed”: false
}

But file actually created with some encoded string on the target host:

$ cat /tmp/testfile.txt
▒▒some test text

You’ll still need to get powershell to return json to standard out, otherwise ansible will not be able to understand what happened when your module ran.

Matt Martz’s example above is about as simple as a module could be - the Exit-Json cmdlet returns the $result object as JSON.

Hope this helps,

Jon

Yes, got the same error with json out module as:
serverA: mymodule2.ps1

`
#!/usr/bin/powershell

WANT_JSON

POWERSHELL_COMMON

$result = New-Object psobject
Set-Attr $result “msg” “test”
Exit-Json $result
`

ServerA$ansible ServerB -m mymodule2.ps1

FAILED! => { "changed": false, "failed": true, "module_stderr": "", "module_stdout": "\u001b[?1h\u001b={\"msg\":\"test\"}\r\n", "msg": "MODULE FAILURE", "parsed": false }