Parsing output from win_powershell and format-list

I would like to get structured output of a list of processes on a WIndows machine. My thought was to do:

ansible -m ansible.windows.win_powershell -a 'script="Get-Process | Format-table -Property Name,Product,PID"'

But the output looks like:

    "output": [
        {
            "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "033ecb2bc07a4d43b5ef94ed5a35d280",
            "autosizeInfo": null,
            "groupingEntry": null,
            "pageFooterEntry": null,
            "pageHeaderEntry": null,
            "shapeInfo": {
                "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "830bdcb24c1642258724e441512233a4"
            }
        },
        {
            "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "9e210fe47d09416682b841769c78b8a3",
            "groupingEntry": null,
            "shapeInfo": null
        },
        {
            "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "27c87ef9bbda4f709f6b4002fa4af63c",
            "formatEntryInfo": {
                "ClassId2e4f51ef21dd47e99d3c952918aff9cd": "cf58f450baa848ef8eb3504008be6978",
                "listViewFieldList": "Microsoft.PowerShell.Commands.Internal.Format.ListViewField Microsoft.PowerShell.Commands.Internal.Format.ListViewField"
            },
            "outOfBand": false,
            "writeStream": {
                "String": "None",
                "Type": "Microsoft.PowerShell.Commands.Internal.Format.WriteStreamType",
                "Value": 0
            }
        },
....

Can I get the objects to render as strings? Some other way to get what I want? Thanks!

As a general rule, Ansible requires a json return object from all modules. If I’m not mistaken, win_powershell runs the entire script as an $object and automatically passes the output to | ConvertTo-Json to make it parse-able by Ansible and reduce the burden of Ansiblizing your existing powershell scripts. To get only “string”, then you would need to return only [System.String] instead of some [Microsoft.PowerShell.Commands.Internal.Format.*] class object, but it would still be a string object in the "output": [] json you see now.

So there’s 2 approaches you could take.

  1. Pre-process the results in your PowerShell script so that it returns exactly what you want.
  2. Have Ansible parse the json object by registering the output to a variable and manipulating it in the playbook yaml.

Both options have merit. Pre-processing it is great at distributing the workload from the Ansible control node to the remote inventory hosts. However, if you need lots of data for complex operations later in your playbook, you may want to parse the results in Ansible.

E.g. for option 1

---
- hosts: all
  tasks:
# Get only the process we want, and pipe it to "Select-Object" instead of "Format-Table"
# This is still an object, but it is more usable than the FT result and 
# more convenient than a String in Ansible.
    - name: Get explorer processes
      ansible.windows.win_powershell:
         script: |
           Get-Process explorer | Select-Object -Property Name,Product,Id
     register: explorer_processes

    - name: Display explorer processes
      ansible.builtin.debug:
        msg: "{{ explorer_processes.output }}"

option 2

---
- hosts: all
  tasks:
# get properties of all processes and filter it later
# ps: noticed while testing that powershell hangs or takes a long time to compute when trying to convert *all* properties to json
    - name: Get all processes
      ansible.windows.win_powershell:
         script: |
           Get-Process | Select-Object -Property Name,Product,ID
      register: processes

    - name: Display explorer processes
      vars:
        json_query: "output[?Name=='explorer'].{Name: Name,Product: Product, PID: Id}"
      ansible.builtin.debug:
         msg: "{{ processes| community.general.json_query(json_query) }}"

There’s probably a way to parse the output in Ansible without the community.general collection by using the map and/or other builtin filters, but I don’t have the time right this second to work that out.

Edit: Example output from both samples above:
ansible-playbook test.yml -i windows

Output
PLAY [all] *****************************************************************************************************************************************************************************************************************************************************************************

TASK [Get explorer processes] **********************************************************************************************************************************************************************************************************************************************************
changed: [172.17.176.1]

TASK [Display explorer processes] ******************************************************************************************************************************************************************************************************************************************************
ok: [172.17.176.1] => {
    "msg": [
        {
            "Id": 10996,
            "Name": "explorer",
            "Product": "Microsoft® Windows® Operating System"
        }
    ]
}

TASK [Get all processes] ***************************************************************************************************************************************************************************************************************************************************************
changed: [172.17.176.1]

TASK [Display explorer processes] ******************************************************************************************************************************************************************************************************************************************************
ok: [172.17.176.1] => {
    "msg": [
        {
            "Name": "explorer",
            "PID": 10996,
            "Product": "Microsoft® Windows® Operating System"
        }
    ]
}

PLAY RECAP *****************************************************************************************************************************************************************************************************************************************************************************
172.17.176.1               : ok=4    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

In both cases, we get a list of dictionaries for the “explorer” process, which almost always has at least 1 process.

2 Likes

Thank you - Select-Object returns exactly what i wanted.

1 Like