Ansible is a great tool to manage any Linux or Windows host. However it is missing some key tools and features. Here is a playbook and instructions to gather all installed programs on a Windows host.

Start with creating a new role, I named mine facts.

Create the facts\tasks\main.yml file and add the following

- name: create Scripts dir
    path: C:\Scripts
    state: directory 

- name: create Scripts facts dir
    path: C:\Scripts\facts
    state: absent        

- name: copy custom facts file
    src: getFacts.ps1
    dest: C:\Scripts\

- name: gather extra facts
    fact_path: C:\Scripts

- name: Set intermediate fact
    vars_hack: ""

- name: set program facts
    one_fact: ansible_getFacts
    var_hack:  "" 
- name: delete json file 
    path: "/.json"
    state: absent
  failed_when: false
  delegate_to: localhost

- name: Dump all vars
  action: template src=templates/dumpall.j2 dest="/.json"
  delegate_to: localhost

- name: add to db
  delegate_to: localhost
  ignore_errors: true

Now create the facts/files/getFacts.ps1 file and add the follwoing below. This file will be copied to each Windows host and run return a dictionary of all installed programs.

#sourced from
$packages = Get-WmiObject -Class Win32_Product
$returnpackages = @{}
foreach ($package in $packages)
   $subpackagedictionary = @{"Name" = $Package.Name; "Version" = $Package.Version; "Caption" = $Package.Caption;}
   $returnpackages.Add($Package.Name, $subpackagedictionary)
#Write-Host $returnpackages."Google Chrome".Name
#Write-Host $returnpackages."Google Chrome".Version

For debugging purposes you may want to create JSON files from the returned dictionary. To do so create a facts/templates/dumpall.j2 and add the following.

  {{ vars_hack | to_json }}

Create the facts\files\ and add the following below. This files erases passwords dumped in the the json files.

#!/usr/bin/env python
# orginal found at

import os
import json

from os import listdir
from os.path import isfile, join

tempfolder = '../roles/facts/files/data/json/'

if not os.path.isdir(tempfolder):

onlyfiles = [f for f in listdir(tempfolder) if isfile(join(tempfolder, f))]

for file in onlyfiles:
  host_name = str(file).replace('.json','')  ##I am using host ips, to use hostnames use str(file).split(".")[3]
  with open(os.path.join(tempfolder, file),'r+') as data_file:
      data = json.load(data_file)
      data['ansible_password'] = ''
      data['ansible_password_ad'] = ''
  with open(tempfolder+'/'+file, 'w+') as outfile:
    json.dump(data, outfile, sort_keys=True, indent=2, separators=(',', ': '))

Create one last file the vars file for the role. Create vars/main.yml and add the following.

json_files: '../roles/facts/files/data/json/'
host_program_csv: '../roles/facts/files/data/programs'

Now install the redis service. For Centos 7

yum install redis
systemctl enable redis
systemctl start redis

Generate a hash for redis

echo "redis-password-string" | sha256sum 

Edit the redis config file in /etc/redis.confand find the line requirepass and insert the generated hash

Edit your base ansible.cfg usualy in the first directory of your ansible setup and add the line

fact_caching_connection = <redis-ip>:6379:0:<redis-hash>

Updated: 2/7/2019