[PYTHON] Install security update (KB) individually on Windows Server with Ansible Part 2 ~ Dynamically acquire multiple MSU files under the directory with the ls command and install in a loop

0. Introduction

This is a sample Ansible playbook that installs KB from Ansible to Windows2012ServerR2 using MSU files. I think you can do something similar with Chef.

This post is an updated version of the previous Post. The MSU file under the patch directory is dynamically acquired by the ls command, and updated to install by looping for the MSU file (block loop with_itmes * include / items / c03e7cbce8608b1c55f1), jinja2 filter regex_replace etc.) In addition, although there was no previous time, we added a KB installation check before and after the blook process and KB installation. In the case of KB that is not reflected without restarting? Is Comment out the check command part after installation (lines 17 to 20 of win_patch_child.yml), or For the check after installation, please use another playbook or check with Serverspec etc.

The following is unchanged from the previous time. It's a muddy method using raw modules, but there are few cases related to Windows, so it's just for reference. Actually, I think that it is necessary to raise / lower the service, reboot, and control the upper LB, but only the KB installation is described simply. Also, I am using pkgmgr instead of DISM for installation.

1. Rough flow

On the Ansible server side

  1. Create a patch directory in the playbook execution directory in advance and manually / automatically download the target msu file under it.

win_patch.yml

  1. Dynamically acquire the file name under the patch directory with the ls command and store it in the ls command result variable of the playbook.
  2. Playbook ** win_patch_child.yml ** that dynamically loops (with_items) for the files that exist in the ls command result variable and installs the KB file only when the extension is an MSU file. Call (ʻinclude), dynamically process the acquired MSU file name with a regular expression by regex_replace`, and set it as a variable such as KB number.

Below from Ansible Server to target Windows

win_patch_child.yml

  1. Create a directory to copy the msu file
  2. Copy the msu file
  3. Compress and decompress the msu file
  4. Silent installation with pkgmgr

2. playbook etc.

win_patch.yml


---
- hosts: win
# Don't gather hosts facts for performance
  gather_facts: no
# Setting the task
  tasks:
   - name: "Get Win pacth name"
     shell: ls patch
     delegate_to: localhost
     register: command_result

   - name: "Install Win patch"
     include: win_patch_child.yml kb_msu={{ item }}
     with_items: "{{ command_result.stdout_lines }}"
     when: "'.msu' in item"
     vars:
       kb_src_dr:             "patch"
       kb_dest_dr:            "c:/work/"
       kb_src:                "{{ kb_src_dr }}/{{ kb_msu }}"
       kb_dest:               "{{ kb_dest_dr }}/{{ kb_msu }}"
       kb_xml:                "{{ kb_msu | regex_replace('.msu','.xml') }}"
       kb_no:                 "{{ kb_msu | regex_replace('^.*-KB(\\d*)-.*msu$','\\1') }}"
       check_command:         "wmic qfe | findstr {{ kb_no }}"
# When I use wusa/pkgmagr as follows vars.
       decompression_command: "wusa {{kb_dest}} /extract:{{ kb_dest_dr }}"
       install_command:       "pkgmgr /n:{{ kb_dest_dr }}{{ kb_xml }} /quiet /norestart"
       uninstall_command:     "wusa /uninstall /kb:{{ kb_no }} /quiet /norestart"
# When you use expand/Dism, you comment out a line of wusa/pkgmagr, and please use a variable as follows.
#       kb_cab:                "{{ kb_msu | regex_replace('.msu','.cab') }}"
#       decompression_command: "expand -f:{{kb_cab}} {{ kb_dest_dr }}{{ kb_msu }} {{ kb_dest_dr }}KB{{ kb_no }}"
#       install_command:       "Dism /Online /Add-Package /PackagePath:{{ kb_dest_dr }}KB{{ kb_no }} /quiet /norestart"
#       uninstall_command:     "wusa /uninstall /kb:{{ kb_no }} /quiet /norestart"

win_patch_child.yml


---
  - name: Check KB
    raw: "{{ check_command }}"
    register: command1_result
    failed_when: command1_result.rc not in [ 0 , 1 ]

  - block:
      - debug: msg="Block START ----------------------"
      - name: create directory
        win_file: path={{ kb_dest_dr  }} state=directory
      - name: copy the file
        win_copy: src={{ kb_src }} dest={{ kb_dest }} mode=0755
      - name: decompression the msu file
        raw: "{{ decompression_command }}"
      - name: install KB
        raw: "{{ install_command }}"
      - name: Check KB
        raw: "{{ check_command }}"
        register: command2_result
        failed_when: "'KB{{ kb_no }}' not in command2_result.stdout"
      - debug: msg="Block END ------------------------"
    when: "'KB{{ kb_no }}' not in command1_result.stdout"

    rescue:
      - debug: msg="Rescue START ---------------------"
      - debug: msg="install {{ kb_no }} is error"
      - name: uninstall KB
        raw: "{{ uninstall_command }}"
      - debug: msg="Rescue END -----------------------"

    always:
      - debug: msg="Always START ---------------------"
      - debug: msg="before '{{ check_command }}' {{ command1_result.stdout_lines }}"
        when: command1_result is defined
      - debug: msg="after  '{{ check_command }}' {{ command2_result.stdout_lines }}"
        when: command2_result is defined
      - debug: msg="Always END -----------------------"

  - debug: msg="Because KB{{ kb_no }} had been already installed, I skipped installation.
                This is result of the check command '{{ check_command }}'
                {{ command1_result.stdout_lines }}"
    when: "'KB{{ kb_no }}' in command1_result.stdout"

Inventory file hosts

[win]
win0[1:2]

[win:vars]
ansible_ssh_user=ansible
ansible_ssh_pass=ansibleansible
ansible_ssh_port=5985
ansible_connection=winrm

3. Other

Under patch directory

patch/
- Windows8.1-KB3079904-x64.msu
- Windows8.1-KB3140735-x64.msu
- openssl-1.0.1e-48.el6_8.1.x86_64.rpm

ansible --version

# ansible --version
ansible 2.2.0 (devel 394430a61e) last updated 2016/06/28 13:25:07 (GMT +900)
  lib/ansible/modules/core: (detached HEAD 3c6f2c2db1) last updated 2016/06/28 13:25:30 (GMT +900)
  lib/ansible/modules/extras: (detached HEAD 1c36665545) last updated 2016/06/28 13:25:37 (GMT +900)
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides

Recommended Posts

Install security update (KB) individually on Windows Server with Ansible Part 2 ~ Dynamically acquire multiple MSU files under the directory with the ls command and install in a loop
Replace the directory name and the file name in the directory together with a Linux command.
How to list files under the specified directory in a list (multiple conditions / subdirectory search)