1

Does anyone have an example of a working Powershell script to create a custom fact on Windows for Ansible?

I tried something similar on Linux and it works fine but on Windows I cannot get it to work. It does not help that I cannot find any example on the internet either!

I have tried a number of variations of the following Powershell script but am unable to get it to work. To be clear, I am able to display the actual custom fact but am unable to access it using say

ansible_facts.some_var

$myjson = @"
{  
  "some_var": "some_value"
}
"@

Write-Output $myjson
  • Variations attempted
  • Tried converting to JSON via Write-Output $myjson | ConvertToJson
  • Added/removed quotes
U880D
  • 8,601
  • 6
  • 24
  • 40
souser
  • 5,868
  • 5
  • 35
  • 50

2 Answers2

3

In example, I use the following Powershell script with the name installed_software.ps1 to get the installed software:

# Get installed software

Get-WmiObject -Class Win32_Product | select Name, Version

Put the Powershell script in the path c:\temp\facts on the Windows Remote Node and call it from the Ansible Control Node in example with

ansible win -m setup -a 'fact_path=C:/TEMP/facts gather_timeout=20 gather_subset=!hardware,!network,!ohai,!facter'

See also the documentation about the setup module.

The most important thing is: Do not output JSON! The setup module in Windows expect raw hashtables (annot.: see Create Hashtable from JSON for how to get such), arrays, or other primitive objects.

My output within the JSON looks like:

...
    "ansible_installed_software": [
      {
        "Name": "Office 16 Click-to-Run Extensibility Component",
        "Version": "16.0.15427.20178"
      },
      {
        "Name": "Office 16 Click-to-Run Localization Component",
        "Version": "16.0.14131.20278"
      },
...
U880D
  • 8,601
  • 6
  • 24
  • 40
Oliver Gaida
  • 1,722
  • 7
  • 14
2

I've wrestled with Windows custom facts in the past. This is what I do:

This is a test facts file you need to place on your Windows server. I use Ansible to put it in place:

$InstanceType = $(Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/instance-type)
$AvailZone = $(Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/placement/availability-zone)
$AMI_ID = $(Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/ami-id)
@{
    local = @{
        local_facts = @{
            cloud = 'AWS'
            instance_type = $InstanceType
            avail_zone = $AvailZone
            ami_id = $AMI_ID
            region = 'eu-west-1'
            environment = 'DIT'
            Support_Team = 'Win_Team'
            Callout = '6-8'
        }
    }
}

You don't need to nest the local & local_facts, that's just my personal preference.

At the top of the file, I've added a few variables to grab the AWS metadata but you can change these to something else.

I put my file in C:\TEMP\facts then run ansible:

ansible win -m setup -a fact_path=C:/TEMP/facts

and you should get out something like this:

"ansible_local": {
    "local": {
        "local_facts": {
            "Callout": "6-8",
            "Support_Team": "Win_Team",
            "ami_id": "ami-07d8c98607d0b1326",
            "avail_zone": "eu-west-1c",
            "cloud": "AWS",
            "environment": "DIT",
            "instance_type": "t2.micro",
            "region": "eu-west-1"
        }
    }
},

if you put the JSON into a file, you should be able to query it with a command like this:

cat file1 | jq '.[] .ansible_facts.ansible_local.local.local_facts'
{
  "ami_id": "ami-0c95efaa8fa6e2424",
  "avail_zone": "eu-west-1c",
  "region": "eu-west-1",
  "Callout": "6-8",
  "environment": "DIT",
  "instance_type": "t2.micro",
  "Support_Team": "Win_Team",
  "cloud": "AWS"
}
U880D
  • 8,601
  • 6
  • 24
  • 40
Live_
  • 61
  • 8