Returning Data from a PS script

Hello all,

I am having an issue to where I am executing a powershell script on a group of hosts and cannot get the data to be returned in the way that I want it so that I can iterate over it further down in my playbook. I am pretty sure that I need to build the JSON object in powershell before I return it, but it’s just not working. Please feel free to ask me for any clarification and I will be glad to try and provide any info needed.

Best way to so this is to write a module. This isn't as hard as it might sound. Have a look at win_environment.ps1 it's only about 30 lines of code. First bit checks the module parameters and sets up a $results variable, then the module does its thing and either returns a failure or adds info the the $results variable and completes, passing the results back to the ansible controller where they can be registered and used later in your playbook.

If you still want to write a script, most likely thing that might be messing things up is the fact that you need to be aware that PowerShell has the concept of an output pipe which can contain objects of varying types, and by default many PowerShell built in functions (also called CmdLets) default to sending objects to the output pipe. That's why sometimes you will see

Out-Null

on the ends of some lines of the module code. Thus throws away unwanted objects and lets you control what is in the output pipe, so that only the things you need are converted into json to be returned to the ansible controller.

Hope this helps,

Jon

Before you had sent the message back I think we got started along the right path there. I’m sure there are some things we aren’t doing correctly, but would appreciate your input to help with this. I think we might have a working prototype soon, and once we get it going, then I think it could potentially be extended to become an extras module. Maybe that’s just me being hopeful, but I do think it would be extendable in that manner.

Maybe I was a tad over zealous in my last post. Basically what I am trying to do is gather a bunch of entries about multiple files such that I get the following information returned so that I can then iterate over it and call a different module using the “path” and gather the information using win_file_version.

{
“name”: “Create USB Recovery”,
“path”: “C:\Windows\System32\RecoveryDrive.exe”
},
{
“name”: “Task Manager”,
“path”: “C:\WINDOWS\system32\taskmgr.exe”

},

I have looked at the win_environment.ps1 file, but I don’t see that it adds multiple entries to the returned data. I know I am doing a pisspoor excuse explaining what I am trying to do, but any help could be appreciated.

So here is the script that I am trying to do. rough form of it is

query installed programs
get display name and target_exe
add to variable to be returned by module
iterate over returned paths and do win_file_version on target_exe

Rough code as of now is…

`

#!powershell

WANT_JSON

POWERSHELL_COMMON

$path = “C:\ProgramData\Microsoft\Windows\Start Menu\Programs”
$items = Get-ChildItem -Recurse -Path $path -Include *.lnk
$Shell = New-Object -ComObject WScript.Shell
$result = @{
changed = $false
installed_progs = @{}
}
$intalled_programs = New-Object System.Collections.Arraylist

foreach ($item in $items) {

$object = new-object psobject @{
name = $item.BaseName.tolower()
path = $Shell.CreateShortcut($item).targetpath.tolower()
}

if ($object.path.endswith(‘exe’)) {
$result.installed_progs.add($item.BaseName.toLower(), $Shell.CreateShortcut($item).targetpath.tolower())
}
}

[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
Exit-Json $result

`

Didn’t state explicitly, but the code above is not working and is the Module that I am trying to get integrated.

I don’t know anything about Power Shell, but to return variables to Ansible, you need to return them in JSON format under the ‘ansible_facts’ key. See http://docs.ansible.com/ansible/dev_guide/developing_modules_general.html#module-provided-facts

So here’s the script and data as I have them and while not 100% correct with the output it’s close enough until I can figure it out properly.

`

#!powershell

WANT_JSON

$path = “C:\ProgramData\Microsoft\Windows\Start Menu\Programs”
$items = Get-ChildItem -Recurse -Path $path -Include *.lnk
$Shell = New-Object -ComObject WScript.Shell
$result = @{
changed = $false
installed_progs = @()
}

foreach ($item in $items) {

$object = new-object psobject @{
name = $item.BaseName.tolower()
path = $Shell.CreateShortcut($item).targetpath.tolower()
}

if ($object.path.endswith(‘exe’) -and $object.path -like “Program”) {
$result.installed_progs+=$object
}
}

[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null

echo $result | convertto-json -compress -depth 99

`

and the play that I run to get the data out as I am doing it via module

`

and the final output of the bottom part of the play to output the gathered data

`

ok: [REMOVED] => (item={u’_ansible_parsed’: True, u’changed’: False, u’_ansible_no_log’: False, u’_ansible_item_result’: True, u’win_file_version’: {u’file_private_part’: u’0’, u’file_build_part’: u’0’, u’file_version’: u’2, 3, 0, 0’, u’product_version’: u’2.3 beta 2’, u’path’: u’c:\program files\teracopy\teracopy.exe’, u’file_major_part’: u’2’, u’file_minor_part’: u’3’}, u’item’: {u’path’: u’c:\program files\teracopy\teracopy.exe’, u’name’: u’teracopy’}, u’invocation’: {u’module_name’: u’win_file_version’}}) => {
“<type ‘dict’>”: “VARIABLE IS NOT DEFINED!”,
“item”: {
“changed”: false,
“invocation”: {
“module_name”: “win_file_version”
},
“item”: {
“name”: “teracopy”,
“path”: “c:\program files\teracopy\teracopy.exe”
},
“win_file_version”: {
“file_build_part”: “0”,
“file_major_part”: “2”,
“file_minor_part”: “3”,
“file_private_part”: “0”,
“file_version”: “2, 3, 0, 0”,
“path”: “c:\program files\teracopy\teracopy.exe”,
“product_version”: “2.3 beta 2”
}
}
}

`

You need to return your variables under the “ansible_facts” key. Something like:

{ "changed": false, "ansible_facts": { "applications": { "installed_progs": [ { "name": "7-zip file manager", "path": "c:\\program files\\7-zip\\7zfm.exe" }, } } }

I know i suggested writing a module, but one thing you can do which might be close to what you are trying is using a script to add custom facts to your systems. There's a nice write up of doing this here. http://hindenes.com/trondsworking/2016/11/05/using-ansible-as-a-software-inventory-db-for-your-windows-nodes/
This might be easier as you don't have to create an entire module.
As you have seen, you can return data from a script, but by extending facts, it is more straightforward to use the extra info you have gathered later in your playbook.

Hope this helps,

Jon

That’s the road I have been digging in to. Been busy with some life things for the past few days. I am going to be able to double down and be able to properly flesh this out. Realistically it should be easy enough(… I hope). Will post back when I can.