File copy/Create folder on Windows server based upon json output from Powershell

142 views
Skip to first unread message

java_cat33

unread,
May 14, 2018, 8:58:42 PM5/14/18
to Ansible Project
Firstly - sorry for the noob question.

I've written a Powershell script that is run from a play that returns in json the name of a zip file.

****Output from Powershell****

{
    "Name":  "latest-ansible v0.1.zip"
}

***playbook***
---
- hosts: all
  vars:
    filename: none
  tasks:
  - name: Install IIS Web-Server with sub features and management tools
    win_feature:
      name: Web-Server
      state: present
      include_sub_features: yes
      include_management_tools: yes
    register: win_feature

  - name: reboot if installing Web-Server feature requires it
    win_reboot:
    when: win_feature.reboot_required

  - name: Run Powershell script and return json including zip file name
    script: files/script.ps1
    register: result

  - set_fact: filename={{result.stdout_lines}}
  - debug: var=result
  - debug: var=filename

  - name: copy files
    win_copy:
      src: C:\Temp\"{{ filename }}"
      dest: C:\Inetpub


Output snippet from running the play is as per below....

TASK [set_fact] ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
task path: /etc/ansible/playbooks/test1/test.yml:22
 [WARNING]: ansible_winrm_cert_validation unsupported by pywinrm (is an up-to-date version of pywinrm installed?)

ok: [servername] => {
    "ansible_facts": {
        "filename": [
            "{",
            "    \"Name\":  \"latest-ansible v0.1.zip\"",
            "}"
        ]
    },
    "changed": false
}

TASK [debug] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
task path: /etc/ansible/playbooks/test1/test.yml:23
 [WARNING]: ansible_winrm_cert_validation unsupported by pywinrm (is an up-to-date version of pywinrm installed?)

ok: [servername] => {
    "result": {
        "changed": true,
        "failed": false,
        "rc": 0,
        "stderr": "",
        "stdout": "{\r\n    \"Name\":  \"latest-ansible v0.1.zip\"\r\n}\r\n",
        "stdout_lines": [
            "{",
            "    \"Name\":  \"latest-ansible v0.1.zip\"",
            "}"
        ]
    }
}

TASK [debug] ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
task path: /etc/ansible/playbooks/test1/test.yml:24
 [WARNING]: ansible_winrm_cert_validation unsupported by pywinrm (is an up-to-date version of pywinrm installed?)

ok: [servername] => {
    "filename": [
        "{",
        "    \"Name\":  \"latest-ansible v0.1.zip\"",
        "}"
    ]
}

TASK [copy files] *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
task path: /etc/ansible/playbooks/test1/test.yml:26
 [WARNING]: ansible_winrm_cert_validation unsupported by pywinrm (is an up-to-date version of pywinrm installed?)

The full traceback is:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/ansible/plugins/action/win_copy.py", line 398, in run
    source = self._find_needle('files', source)
  File "/usr/lib/python2.7/dist-packages/ansible/plugins/action/__init__.py", line 999, in _find_needle
    return self._loader.path_dwim_relative_stack(path_stack, dirname, needle)
  File "/usr/lib/python2.7/dist-packages/ansible/parsing/dataloader.py", line 322, in path_dwim_relative_stack
    raise AnsibleFileNotFound(file_name=source, paths=[to_text(p) for p in search])
AnsibleFileNotFound: Could not find or access 'C:\Temp\"[u'{', u'    "Name":  "latest-ansible v0.1.zip"', u'}']"'
Searched in:
        /etc/ansible/playbooks/test1/files/C:\Temp\"[u'{', u'    "Name":  "latest-ansible v0.1.zip"', u'}']"
        /etc/ansible/playbooks/test1/C:\Temp\"[u'{', u'    "Name":  "latest-ansible v0.1.zip"', u'}']"
        /etc/ansible/playbooks/test1/files/C:\Temp\"[u'{', u'    "Name":  "latest-ansible v0.1.zip"', u'}']"
        /etc/ansible/playbooks/test1/C:\Temp\"[u'{', u'    "Name":  "latest-ansible v0.1.zip"', u'}']"

fatal: [servername]: FAILED! => {
    "changed": false,
    "dest": "C:\\Inetpub",
    "msg": "Could not find or access 'C:\\Temp\\\"[u'{', u'    \"Name\":  \"latest-ansible v0.1.zip\"', u'}']\"'\nSearched in:\n\t/etc/ansible/playbooks/test1/files/C:\\Temp\\\"[u'{', u'    \"Name\":  \"latest-ansible v0.1.zip\"', u'}']\"\n\t/etc/ansible/playbooks/test1/C:\\Temp\\\"[u'{', u'    \"Name\":  \"latest-ansible v0.1.zip\"', u'}']\"\n\t/etc/ansible/playbooks/test1/files/C:\\Temp\\\"[u'{', u'    \"Name\":  \"latest-ansible v0.1.zip\"', u'}']\"\n\t/etc/ansible/playbooks/test1/C:\\Temp\\\"[u'{', u'    \"Name\":  \"latest-ansible v0.1.zip\"', u'}']\"",
    "src": "C:\\Temp\\\"[u'{', u'    \"Name\":  \"latest-ansible v0.1.zip\"', u'}']\""
}
        to retry, use: --limit @/etc/ansible/playbooks/test1/test.retry


What I am trying to do is copy the zip file to a different directory on the same server, create a new folder with name captured in the value in the json output of filename (excluding the .zip - I.E latest-ansible v0.1) and then extract the contents to this new folder.

What do I need to change in my playbook syntax to get this file copy to work leveraging the value in the json output? After I've got this sorted I can tackle the next hurdle :-)

Thanks in advance!

Jordan Borean

unread,
May 14, 2018, 9:58:01 PM5/14/18
to Ansible Project
The issue you are seeing is that you are using the stdout_lines return value which is the stdout of the script that was run but split into a list on each newline. You want to use the stdout return value from the script which would be the full stdout of your json. The task's would look something like this

- name: Run Powershell script and return json including zip file name
  script
: files/script.
ps1
 
register: script_result

# this uses the filter from_json to convert the raw json string to a
# dictionary in Ansible so you can access the variables a lot easier
- name: convert the script result to a dict in Ansible
  set_fact
:
    script_filename
: '{{ script_result.stdout|from_json }}'


- name: copy files
  win_copy
:

    src
: C:\Temp\{{ script_filename.Name }}  # if Name in the JSON is 'latest-ansible v0.1.zip', then src sent to win_copy is 'C:\Temp\latest-ansible v0.1.zip'
    dest
: C:\Inetpub\
    remote_src
: yes  # you need to set this so the copy happens remote to remote, by default src is based on the local Ansible controller

I haven't tested this, but see how you go, it should bring you onto the right track. A few more notes;

  • You are getting warnings saying ansible_winrm_cert_validation is unsupported, the variable should actually be ansible_winrm_server_cert_validation, if you remove the definition of ansible_winrm_cert_validation then those warnings will go away
  • In your win_copy task, you quoted the jinja2 block, you only need to quote it when the value starts with a block like so
# doesn't need quoting as the value itself doesn't start with {
key
: value/{{ variable }}

# needs to be quoted as the value does start with {
key
: "{{ variable }}"

Thanks

Jordan

java_cat33

unread,
May 14, 2018, 10:17:32 PM5/14/18
to Ansible Project
Thanks Jordan! That code worked a treat - really appreciate your assistance and detailed explanations below.

java_cat33

unread,
May 14, 2018, 11:17:15 PM5/14/18
to Ansible Project
Jordan do you know how to strip the ".zip" off the file name? I've been looking at http://jinja.pocoo.org/docs/2.10/templates/#truncate but haven't cracked it yet.

Jordan Borean

unread,
May 14, 2018, 11:56:20 PM5/14/18
to Ansible Project
Hey

There are a few ways to do this, they usually revolve around using filters to "filter" the value into something else. Ansible has a few filters available outside of the standard Jinja2 functions which can be found here https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html. In your case you want to use the splitext to split the path between the path/filename and the extension like so;

src: C:\Temp\{{ (script_filename.Name|splitext)[0] }}

What we do here is pass the value of script_filename.Name to the filter splitext and that ultimately returns a value, in this case returns a tuple of (path without extension, extension). We don't want the extension so we only get the first element from the return value and because it is a 0 based index, 0 is the first element.

Thanks

Jordan

java_cat33

unread,
May 15, 2018, 12:20:44 AM5/15/18
to Ansible Project
Nice - thanks Jordan. That's easier than what I've just done....

win_file:
      path: C:\inetpub\{{ script_filename.Name | regex_replace('.zip$','') }}

Thanks again!

java_cat33

unread,
May 17, 2018, 12:49:07 AM5/17/18
to Ansible Project
Sorry - I've got another question(s) related to this. I've modified the PS script to return 2 x json outputs, each assigned to a different PS variable. Each output contains a different file name.

Is it possible to return two outputs to the playbook ran off the task that runs the PS script? Can 2 x variables in the play be registered for this task? Not just script_result?

Another option would be to create a separate script - each script returns a different string that is parsed to playbook......... or create a hashtable...... @ { file1 = string1; file2 = string 2} - then convert this to json? 

Assuming the hashtable is the recommended approach - the returns json could then be searched for the relevant key name?

java_cat33

unread,
May 17, 2018, 12:57:30 AM5/17/18
to Ansible Project
Updated - changed script to now add the two variables into a hashtable that is converted to json - assume this is the correct approach. This can be returned to the script_output registered in the play.

Jordan Borean

unread,
May 17, 2018, 3:13:24 AM5/17/18
to Ansible Project
Yep, I would create a hashtable, convert that to JSON and output that. That way you can parse that into Ansible easily and select whatever key you want. This is how the PowerShell modules work as well.

Thanks

Jordan

Lee Drew

unread,
May 17, 2018, 6:46:35 AM5/17/18
to ansible...@googlegroups.com
Cool. Thanks Jordan. Works a treat.

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/dee17ca7-70a6-4103-9a05-befdf1197e02%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages