ansible.windows
ansible.windows copied to clipboard
win_shell: captured stdout is incomplete when multi-line string is used in conjonction with cmd executable
SUMMARY
When using win_shell
with the cmd
executable and a multi-line string, the captured stdout is limited to the first command executed.
ISSUE TYPE
- Bug Report
COMPONENT NAME
win_shell
ANSIBLE VERSION
ansible [core 2.15.0]
config file = /home/mtarral/kafl/kafl/examples/templates/windows/ansible.cfg
configured module search path = ['/home/mtarral/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/mtarral/kafl/kafl/examples/venv/lib/python3.10/site-packages/ansible
ansible collection location = /home/mtarral/.ansible/collections:/usr/share/ansible/collections
executable location = /home/mtarral/kafl/kafl/examples/venv/bin/ansible
python version = 3.10.6 (main, May 29 2023, 11:10:38) [GCC 11.3.0] (/home/mtarral/kafl/kafl/examples/venv/bin/python3)
jinja version = 3.1.2
libyaml = True
COLLECTION VERSION
ansible-galaxy collection list ansible.windows
# /home/mtarral/kafl/kafl/examples/venv/lib/python3.10/site-packages/ansible_collections
Collection Version
--------------- -------
ansible.windows 1.14.0
CONFIGURATION
CONFIG_FILE() = /home/mtarral/kafl/kafl/examples/templates/windows/ansible.cfg
DEFAULT_STDOUT_CALLBACK(/home/mtarral/kafl/kafl/examples/templates/windows/ansible.cfg) = yaml
EDITOR(env: EDITOR) = vim
OS / ENVIRONMENT
- Ubuntu 22.04.1
STEPS TO REPRODUCE
- name: Deploy
hosts: default
tasks:
- name: execute win_shell free form
win_shell: |
echo 'First line'
echo 'Second line'
echo 'Third line'
args:
executable: cmd
register: output
- name:
debug:
var: output.stdout_lines
EXPECTED RESULTS
The stdout_lines should have contained the 3 strings that were echoed by cmd free-form script
ACTUAL RESULTS
qemu.windows: TASK [Gathering Facts] *********************************************************
qemu.windows: ok: [default]
qemu.windows:
qemu.windows: TASK [execute win_shell free form] *********************************************
qemu.windows: changed: [default] => changed=true
qemu.windows: cmd: |-
qemu.windows: echo 'First line'
qemu.windows: echo 'Second line'
qemu.windows: echo 'Third line'
qemu.windows: delta: '0:00:00.140708'
qemu.windows: end: '2023-06-13 23:58:45.769936'
qemu.windows: rc: 0
qemu.windows: start: '2023-06-13 23:58:45.629227'
qemu.windows: stderr: ''
qemu.windows: stderr_lines: <omitted>
qemu.windows: stdout: |-
qemu.windows: 'First line'
qemu.windows: stdout_lines: <omitted>
qemu.windows:
qemu.windows: TASK [debug] *******************************************************************
qemu.windows: ok: [default] =>
qemu.windows: output.stdout_lines:
qemu.windows: - '''First line'''
qemu.windows:
qemu.windows: PLAY RECAP *********************************************************************
qemu.windows: default : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
git clone https://github.com/Wenzel/kafl.targets -b bug_win_shell_stdout
cd templates/windows
python3 -m venv venv
source venv/bin/activate
pip install ansible==8.0.0 pywinrm
packer build -var-file win10.pkrvars.hcl -on-error=ask windows.pkr.hcl
I believe this is a limitation of cmd itself, essentially this command is running cmd.exe /c {{ raw_params }}
and it is up to cmd to parse this. It seems like it doesn't work with newline literals so you would have to use &&
or ||
to chain the commands accordingly.
- win_shell: >-
echo "one" &&
echo "two" &&
echo "three"
args:
executable: cmd
Thanks, I see.
while the solutoon you proposed works, it breaks a bit the expected usability of the multi-line form. If we take the example from the documentation:
- name: Run multi-lined shell commands
ansible.windows.win_shell: |
$value = Test-Path -Path C:\temp
if ($value) {
Remove-Item -Path C:\temp -Force
}
New-Item -Path C:\temp -ItemType Directory
Here it feels like we are writing a real powershell script, not just a succession of chained commands. It would be nice to keep the same feeling with cmd.
What about dumping the received string inside a temporary bat script that would be executed ?
It seems more robust that way, and it would be more consistent with the user's expectations in my opinion.
Here it feels like we are writing a real powershell script, not just a succession of chained commands. It would be nice to keep the same feeling with cmd.
Sure it's because PowerShell supports such a thing whereas cmd.exe
does not seem to.
What about dumping the received string inside a temporary bat script that would be executed ?
When a custom executable is used we run it through the command line {{ executable }} /c {{ raw_params }}
. While yes we could have it written to a temporary file we do not and I don't think we should as now the data being provided will have touched the disk. Having a file be created now means the script mentioned can persist even beyond it being deleted by us and if it contains sensitive values that means we've exposed those values. It also means that we would need to prepend things like @echo off
to stop it from echoing the commands. It's not a dealbreaker but having to modify something that is run never sits well with me.
It's also already possible using the script
module which does the work for you to temporarily copy across the file and execute it.
- script:
cmd: test.bat
executable: cmd.exe /c
The test.bat
was stored on the controller side with
@echo off
echo "one"
echo "two"
The output after running
changed: [SERVER2022] => changed=true
rc: 0
stderr: ''
stderr_lines: <omitted>
stdout: |-
"one"
"two"
stdout_lines: <omitted>
Script already has the expectation that a file is copied across whereas win_shell
is known to run in memory.