プロビジョニング・ツール(環境構築ツール)の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
---
- hosts: all
gather_facts: no
tasks:
- name: インストールされているプログラム情報を取得
script: files/get-installed.ps1
register: installed_result
- debug: var=installed_result.stdout_lines
[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-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形式ファイルに保存するよう修正します。ファイルのパスはコマンドラインオプションで指定することとします。
Param($csvpath)
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |
foreach {Get-ItemProperty $_.PSPath} |
select DisplayName,DisplayVersion,InstallDate,Publisher |
export-csv $csvpath -notype
playbookを修正します。
---
- 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に指定したパスの下にファイルを保存します。ただし、ファイル名を管理ノード毎にユニークになるようにしないとファイル名が衝突するので注意が必要です。
work
+-- outdir
+-- lima
+-- C:
+-- Windows
+-- Temp
+-- installed_lima.csv
Ansibleで各管理ノードからプログラムのインストール情報を取得(その3)
収集するインストール情報を、特定のプログラムについて絞り込みたいとします。
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
スクリプトの引数に、絞り込む名前を指定します。指定には正規表現が使えます。
- name: インストールされているJavaプログラムの一覧情報をCSVファイルに生成
script: files/get-installed.ps1 "^Java" "{{ csvpath }}"