Ansible Windows Powershell over SSH not accepting pipelined input

I’m currently running into a problem with with the way the exec_wrapper receives commands/scripts to run. I’m trying to run the below on ansible core 2.16.3, I have also tried on ansible core 2.18.7 but I’m getting the same error.

The connection I’m performing goes like this:

My laptop --(SSH)-> CyberArk --(SSH)-> my_windows_server

The ansible.cfg file contains the following:

[ssh_connection]
gather_timeout = 90
pipelining = true
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

My inventory file looks like this:

all:
  vars:
    ansible_connection: ssh
    ansible_shell_type: powershell
  hosts:
    my_windows_server:

ftp:
  hosts:
    my_windows_server:

My playbook looks like this:

---
- name: Configure Windows Firewall
  hosts: ftp
  gather_facts: no
  tasks:
      # Test connectivity to a windows host
      # ansible winserver -m ansible.windows.win_ping

    - name: Execute whoami in PowerShell
      ansible.windows.win_shell: "whoami"

I turned on powershell transcription on the server and managed to get the script being run, which looks like this and seems fairly normal based on what I have been able to piece together:

&chcp.com 65001 > $null
if ($PSVersionTable.PSVersion -lt [Version]"3.0") {
'{"failed":true,"msg":"Ansible requires PowerShell v3.0 or newer"}'
exit 1
}
$exec_wrapper_str = $input | Out-String
$split_parts = $exec_wrapper_str.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
If (-not $split_parts.Length -eq 2) { throw "invalid payload" }
Set-Variable -Name json_raw -Value $split_parts[1]
$exec_wrapper = [ScriptBlock]::Create($split_parts[0])
&$exec_wrapper

However that is followed by the following error which is the same error I see in the ansible output:

PS>CommandInvocation(Out-String): "Out-String"
>> ParameterBinding(Out-String): name="InputObject"; value="Exception calling "Create" with "1" argument(s): "At line:159 char:5
+     {"module_entry": "IyFwb3dlcnNoZWxsCgojIENvcHlyaWdodDogKGMpIDIwMTc ...
+     ~
Unexpected token '{' in expression or statement.""
Exception calling "Create" with "1" argument(s): "At line:159 char:5
+     {"module_entry": "IyFwb3dlcnNoZWxsCgojIENvcHlyaWdodDogKGMpIDIwMTc ...
+     ~
Unexpected token '{' in expression or statement."
At line:10 char:1
+ $exec_wrapper = [ScriptBlock]::Create($split_parts[0])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ParseException
Exception calling "Create" with "1" argument(s): "At line:159 char:5
+     {"module_entry": "IyFwb3dlcnNoZWxsCgojIENvcHlyaWdodDogKGMpIDIwMTc ...
+     ~
Unexpected token '{' in expression or statement."
At line:10 char:1
+ $exec_wrapper = [ScriptBlock]::Create($split_parts[0])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ParseException
Exception calling "Create" with "1" argument(s): "At line:159 char:5
+     {"module_entry": "IyFwb3dlcnNoZWxsCgojIENvcHlyaWdodDogKGMpIDIwMTc ...
+     ~
Unexpected token '{' in expression or statement."
At line:10 char:1
+ $exec_wrapper = [ScriptBlock]::Create($split_parts[0])
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ParseException

windows ssh powershell

The exec wrapper will write 2 things to stdin, the actual execution code then the module JSON payload. These values are separated from 4 null byte chars so the execution code should be $split_parts[0] while the module json should be $split_parts[1]. In your case it seems like the code isn’t receiving the first part and is trying to smuggle the module JSON payload as the first part which will fail.

I would try to replicate this without whatever this CyberArk SSH thing is to try and see whether it’s a problem on the SSH server side, whatever CyberArk is doing, or how Ansible it sending the JSON. The other curious thing is seeing

ParameterBinding(Out-String): name=“InputObject”; value=…

This would indicate that potentially you have module logging enabled in PowerShell which is certainly not something you normally would see. This is an unusual thing to see even in stdout/stderr as it is typically written as a Windows event log. I’m not sure why you see this at all in the output but it’s certainly something to look into further to see if maybe that’s what is consuming the initial input data.

Hi Jordan,

Thanks for the reply, I have just tested by going through another ssh proxy we have and it’s working through that, which seems to confirm your suspicion that CyberArk is the one to blame.

It’s also nice to have some more information about what gets sent through stdin, I was sort of convinced that the json I was seeing was something CyberArk was placing in stdin, but knowing that it’s the module and it’s meant to happen does make things clearer.

I did also end up trying to run commands with ansible.builtin.raw, which did work so I guess it’s truly a problem with CyberArk and stdin, which I will have to take up with them.

Regarding the logging, we do have module logging enabled, and it has most likely been turned on by our Antivirus. The output I grabbed was also from a Powershell Transcript I had set the server up to log, as I thought it would give more details that could help me in troubleshooting it.

Glad to hear you were able to narrow it down. Ultimately I’m not sure why CyberArk might be trimming out the initial stdin line that includes the payload to run. It’ll be interesting if something like this worked outside of Ansible (with whatever is needed to go through CyberArk).

echo -e "line1\nline2" | ssh localhost cat

Thanks for clarifying about the module logging, glad to hear it wasn’t some unknown feature that might pollute the output that I wasn’t aware about.