LoginSignup
8
5

More than 5 years have passed since last update.

AnsibleでWindowsにインストールされているプログラムの情報を取得

Last updated at Posted at 2016-02-14

プロビジョニング・ツール(環境構築ツール)のAnsibleで、Windowsにインストールされているプログラムの情報を取得してみます。

Ansibleは、2.0を使用します(1.9でも適用可能ですが、インベントリ変数名に変更が必要です)。
Windowsは、Windows 7 SP1以降を対象とします。この記事では触れませんが、Windows 7の場合は別途Windows Management Framework 4.0(PowerShell 4.0を含む)をインストールする必要があります。

PowerShellでインストールされているプログラムの情報を取得する方法

Windows OSで、インストールされているプログラムの情報を取得する方法を調べるとまず出てくるのが WMI(Windows Management Instrumentation)です。WMIをコマンドラインから使うコマンドとしてwmicが提供されています。また、PowerShellから使うコマンドレットとしてGet-WmiObjectが提供されています。

PowerShellから次のコマンドを実行すると、インストールされているプログラムの情報が表示されます。

PS > Get-WmiObject Win32_Product

IdentifyingNumber : {5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4}
Name              : Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161
Vendor            : Microsoft Corporation
Version           : 9.0.30729.6161
Caption           : Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161

IdentifyingNumber : {23170F69-40C1-2702-0920-000001000000}
Name              : 7-Zip 9.20 (x64 edition)
Vendor            : Igor Pavlov
Version           : 9.20.00.0
Caption           : 7-Zip 9.20 (x64 edition)

(以下略)

ところが、このwmic(Get-WmiObject)での情報取得は少々時間がかかります(手元のWindows 7マシンでは約1分かかります)。
Ansibleで、このコマンドを各マシンで巡回して実行すると相当な時間がかかってしまうので、直接レジストリから情報を取得することにしました。

PowerShellでは、次のコマンドレットで指定したレジストリのサブキー情報(インストールされているソフトウェア情報)を取得できます。

PS > Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
  • 注)64bit OSの場合、32bitプログラムのインストール情報は別なレジストリに記載されるので、上述のコマンドでは64bitプログラムの情報のみ取得されます。

ここのインストール情報から、次の情報を抜粋して取得するとします。

  • DisplayName
  • DisplayVersion
  • InstallDate
  • Publisher
PS > Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
 foreach {Get-ItemProperty $_.PSPath} |
 select DisplayName,DisplayVersion,InstallDate,Publisher

R for Windows 3.2.1   3.2.1                20150626             R Core Team
Speccy                1.25                                      Piriform
WinMerge 2.14.0.63... 2.14.0.63            20141221             Thingamahoochie S...
Microsoft SQL Serv... 12.0.2000.8          20150802             Microsoft Corpora...
(以下略)

ここまできたら、次はAnsibleからインストール情報を取得する算段を考えます。

Ansibleで各管理ノードからプログラムのインストール情報を取得(その1)

とりあえず動かすことを目標に、次のように、Ansibleのplaybookファイル installed.yml、インベントリファイル hosts を作成し、PowerScriptスクリプトファイル get_installed.ps1 をfilesディレクトリ下に作成します。

ディレクトリ構成
work
  +-- installed.yml
  +-- hosts
  +-- files/
        +-- get_installed.ps1
installed.yml
---
- hosts: all
  gather_facts: no
  tasks:
  - name: インストールされているプログラム情報を取得
    script: files/get-installed.ps1
    register: installed_result
  - debug: var=installed_result.stdout_lines
hosts
[windows]
lima
mike
november

[windows:vars]
ansible_user=foo
ansible_password=fooPassword
ansible_connection=winrm
  • 注)変数名(例: ansible_user)は、Ansible 2.0で変更になった新しい名前を使用しています。従来の変数名(例:ansible_ssh_user)も非推奨となっていますが引き続き使用可能です。
  • パスワードを平文で記述していますが、セキュリティ上配慮が必要な環境ではansible-vaultで暗号化したファイルに記述するとよいでしょう。
get-installed.ps1
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
 foreach {Get-ItemProperty $_.PSPath} |
 select DisplayName,DisplayVersion,InstallDate,Publisher

これを実行すると

work$ ansible-playbook -i hosts installed.yml 

PLAY ***************************************************************************
TASK [インストールされているプログラム情報を取得] ***************************************************
changed: [lima]
changed: [mike]
changed: [november]

TASK [debug] *******************************************************************
ok: [lima] => {
    "installed_result.stdout_lines": [
        "", 
        "DisplayName         DisplayVersion      InstallDate         Publisher          ", 
        "-----------         --------------      -----------         ---------          ", 
        "7-Zip 9.20 (x64 ... 9.20.00.0           20160211            Igor Pavlov        ", 
        "Microsoft Visual... 9.0.30729.6161      20160102            Microsoft Corpor...", 
}
ok: [mike] => {
    "installed_result.stdout_lines": [

(中略)
PLAY RECAP *********************************************************************
lima                       : ok=2    changed=1    unreachable=0    failed=0   
mike                       : ok=2    changed=1    unreachable=0    failed=0 
november                   : ok=2    changed=1    unreachable=0    failed=0 

となります。DisplayNameやPublisherが中途で切れてしまう等の問題があります。
そこで、管理ノード(Windows側)でインストール情報をファイルに保存し、そのファイルを取得する方法を(その2)として実施します。

Ansibleで各管理ノードからプログラムのインストール情報を取得(その2)

work
  +-- installed.yml
  +-- hosts
  +-- files/
  |     +-- get_installed.ps1
  +-- outdir/

管理ノードからファイルを取得して格納するディレクトリ outdirを用意しておきます。

先に、PowerShellスクリプトを、結果をCSV形式ファイルに保存するよう修正します。ファイルのパスはコマンドラインオプションで指定することとします。

get_installed.ps1
Param($csvpath)
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
 foreach {Get-ItemProperty $_.PSPath} |
 select DisplayName,DisplayVersion,InstallDate,Publisher |
 export-csv $csvpath -notype

playbookを修正します。

installed.yml
---
- hosts: all
  gather_facts: no
  vars:
    csvpath: C:\Windows\Temp\installed_{{ inventory_hostname }}.csv
  tasks:
  - name: インストールされているJavaプログラムの一覧情報をCSVファイルに生成
    script: files/get-installed.ps1 "{{ csvpath }}"
  - name: 生成したcsvファイルを取得
    fetch: src={{ csvpath }} dest=./outdir/ flat=yes
  • fetchモジュールは、デフォルトでは制御マシンのdestに指定したパスの下に、管理ノードのホスト名 + srcで指定したパスで取得したファイルを保存します。flat=yesを指定することで、destに指定したパスの下にファイルを保存します。ただし、ファイル名を管理ノード毎にユニークになるようにしないとファイル名が衝突するので注意が必要です。
fetchでflat=yesを指定しなかった場合のファイル保存先パスの例
work
  +-- outdir
        +-- lima
              +-- C:
                    +-- Windows
                          +-- Temp
                                +-- installed_lima.csv

Ansibleで各管理ノードからプログラムのインストール情報を取得(その3)

収集するインストール情報を、特定のプログラムについて絞り込みたいとします。

get_installed.ps1
Param($name, $csvpath)
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
         foreach {Get-ItemProperty $_.PsPath} |
         where {$_.DisplayName -match $name} |
         select DisplayName,DisplayVersion |
         export-csv $csvpath -notype

スクリプトの引数に、絞り込む名前を指定します。指定には正規表現が使えます。

installed.yml(変更箇所)
  - name: インストールされているJavaプログラムの一覧情報をCSVファイルに生成
    script: files/get-installed.ps1 "^Java" "{{ csvpath }}"

参考

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5