D. Smith...
D. Smith...

Reputation: 143

Ansible win_shell with JSON to powershell, works fine other way

I can not get how to get win_shell to send JSON to a powershell script on a windows server. If I run this:

vm:
  annotation: This is a VM
  cdrom:
    type: client
    iso_path: ''
    controller_type: ''
    state: ''
  cluster: ''
- name: "Run script '.ps1'"
    win_shell: D:\scripts\outputValues.ps1 -vm "{{vm}}"
    register: result
  - name: Process win_shell output
    set_fact:
      fullResult: "{{ result.stdout | from_json }}"

I get this string into powershell that I can not even convert TO JSON:

{u'cdrom': {u'controller_type': u'', u'state': u'', u'type': u'client', u'iso_path': u''}, u'cluster': u'', u'annotation': u'This is a VM'}

If I run the script with this:

win_shell: D:\scripts\outputValues.ps1 -vm "{{vm | to_json}}"

All I get is an open curly bracket '{' into powershell.

It does work the other way. As a test, if I call that same powershell script from win_shell and ignore the input in powershell and simply create an object like this and send it back to ansible, it works fine. Why can I send JSON one way and not the other? I have tried vm|to_json etc.

#Powershell
$vmAttribs = @{"type" = "client"; "iso_path" = ""; "controller_type" =""; "state" =""}
$vmObject = New-Object psobject -Property @{
    annotation = 'This is a VM'
    cdrom = $vmAttribs
    cluster = ""
}
$result = $vmObject | ConvertTo-Json -Depth 8
Write-Output $result

ansible gets:

{
    "msg": {
        "cdrom": {
            "controller_type": "",
            "state": "",
            "type": "client",
            "iso_path": ""
        },
        "cluster": "",
        "annotation": "This is a VM"
    },
    "changed": false,
    "_ansible_verbose_always": true,
    "_ansible_no_log": false
}

Upvotes: 2

Views: 2545

Answers (1)

codewario
codewario

Reputation: 21468

What you're seeing is a Python structure signifying JSON notation with Unicode strings (e.g. u'my string value'). Obviously, that's not exactly portable to other runtimes like Powershell, and results in an invalid string.

Reading up on Ansible filters, you will want to use {{ vm | to_json }} to ensure that the data structure is stringified to JSON correctly.

Workaround

I want to stress that this is not the ideal way of getting a JSON object out of Ansible, and a proper solution that doesn't involve hacking out the Unicode identifier from the JSON string is desirable to this.

I don't know enough about Ansible to know why the string becomes { when piping vm to to_json, but here's a workaround that might get you going until someone else can chime in with what is going on with Ansible's filtering here.

In your .ps1 script, you can use the following -replace to remove those u characters before the strings:

$vm = $vm -replace "u(?=([`"']).*\1)"

You can test this by running the following in an interactive terminal:

"{u'cdrom': {u'controller_type': u'', u'state': u'', u'type': u'client', u'iso_path': u''}, u'cluster': u'', u'annotation': u'This is a VM'}" -replace "u(?=([`"']).*\1)"

The pattern matches on the u character that comes immediately before a single-quote or double-quote followed by any number of characters (including none) followed by another single-quote or double quote, whichever was matched the first time. -replace does not require a second argument if you are replacing the pattern with an empty string.

Upvotes: 1

Related Questions