インフラを自動化していても、社内に数台ある Windows Server だけが Ansible の管理外に置かれてしまうケースは多くあります。「Windows は別のツールが必要では」と思われがちですが、Ansible は Linux と同じ Playbook 形式で Windows Server を自動管理できます。手作業のサービス再起動・ソフトウェアインストール・設定ファイルの配置が、Playbook 1本で完結します。さらに、同じ Playbook を何度実行しても結果が変わらない「冪等性(べきとうせい)」がAnsibleの最大の強みです。「すでにインストール済みか」「サービスは起動中か」といった判定を Ansible が内部で自動的に行うため、手順書のような if 分岐を自分で書く必要がありません。
この記事では、Ansible から Windows Server を管理するための接続設定(WinRM)と、ansible.windows collection の主要モジュールの使い方を解説します。WinRM 有効化・インベントリ設定・認証方式の選択から、win_service・win_package・win_copy の実践例まで、RHEL 10 / Rocky Linux 9 のコントロールノードと Windows Server 2022 ターゲットの環境で動作確認しています。
この記事のポイント
・AnsibleはWinRM(ポート5985/5986)でWindows Serverに接続して管理できる
・Windows側でEnable-PSRemoting -Forceを実行してWinRMを有効化する
・インベントリにansible_connection: winrmを設定するだけで既存のPlaybook形式が使える
・同じPlaybookを何度実行しても安全な冪等性で、win_service・win_package・win_copyを一括管理できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
AnsibleがWindowsを管理できる仕組み|WinRMとは
Ansible が Linux を管理するとき、通信の下回りは SSH です。Windows には SSH が標準で有効になっていない(Windows Server 2019 以降は OpenSSH オプションで選択可能ですがデフォルト無効)ため、代わりに WinRM(Windows Remote Management) が使われます。WinRM は Microsoft が策定したリモート管理プロトコルで、SOAP/HTTP をベースにしています。PowerShell のリモーティング(
Invoke-Command -ComputerName)も内部では WinRM を使っており、Windows Server 2008 R2 以降で利用できます。Ansible との関係を整理するとこうなります。
・Linux ターゲット:Ansible コントロールノードが SSH で接続 → Python を実行
・Windows ターゲット:Ansible コントロールノードが WinRM で接続 → PowerShell を実行
Windows ターゲットに Python は不要です。Ansible が WinRM 経由で PowerShell スクリプトを送り込んで実行するため、ターゲット側の準備は「WinRM を有効化する」だけです。Linux サーバーと Windows サーバーが混在するインフラでも、同じ Playbook 構造(vars・roles・handlers・Jinja2 テンプレート)をそのまま使えます。なお、Windows ファイル共有を Samba 経由で行う構成とは異なり、Ansible WinRM は OS の構成変更・ソフトウェア管理・サービス制御に特化した自動化アプローチです(Samba によるファイル共有設定はこちら)。
シェルスクリプトと何が違うのか
PowerShell スクリプトで「IIS がインストール済みかどうか判定して、されていなければインストールする」を書こうとすると、if 文・エラーハンドリング・ロールバック処理が必要になります。Ansible の
win_feature モジュールはその判定を内部で自動的に行います。コードが宣言的になり、「あるべき状態」を記述するだけで済む。これが冪等性の本質です。同じ Playbook を開発環境・ステージング環境・本番環境で実行しても、常に同じ状態が保証されます。WinRM の接続方式を選ぶ|HTTP・HTTPS と認証の関係
WinRM には 2 つのポートがあります。・ポート 5985(HTTP):通信は暗号化されないが設定が簡単。社内テスト環境や VPC 内のプライベートネットワークで使う
・ポート 5986(HTTPS):通信を TLS で暗号化。本番環境での推奨構成
認証方式も複数あります。
・NTLM:ドメイン不要。ローカル管理者アカウントで認証できる。テスト環境で最も設定が簡単
・Kerberos:Active Directory ドメイン環境で推奨。ドメインアカウントを使った安全な認証が可能
・Basic:シンプルだが平文送信のリスクがあるため HTTPS と必ず組み合わせること
・Certificate:クライアント証明書で認証する。高セキュリティ要件の本番環境向け
現場での典型的な選択を整理すると、以下のとおりです。
| 環境 | ポート | 認証方式 | 特徴 |
|---|---|---|---|
| 検証サーバー / プライベートネット内 | 5985(HTTP) | NTLM | pywinrm だけで動き設定が最小 |
| 本番環境(AD ドメインあり) | 5986(HTTPS) | Kerberos | AD ドメイン設計と一体で考える |
| 本番環境(AD ドメインなし) | 5986(HTTPS) | Certificate | クライアント証明書で高セキュリティ |
WinRM を有効化する手順|Windows Server 側の準備
1. PowerShell で WinRM を有効化する
Windows Server に管理者権限で PowerShell を起動し、次のコマンドを実行します。# WinRM リスナーを有効化(HTTP・ポート 5985 でリスナーが作られる) Enable-PSRemoting -Force # 実行後にリスナーを確認 winrm enumerate winrm/config/listener # 出力例(Windows Server 2022 実機) Listener Address = * Transport = HTTP Port = 5985 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint ListeningOn = 192.168.xxx.xxx, 127.0.0.1
Enable-PSRemoting -Force を実行すると次の処理が自動で行われます。・WinRM サービスの起動と自動起動設定
・HTTP リスナー(ポート 5985)の作成
・Windows ファイアウォールの例外追加(ドメインおよびプライベートプロファイル)
パブリックネットワークプロファイルのサーバーでエラーが出るときは、
Set-NetConnectionProfile でプロファイルを「Private」に変更してから再実行してください。NTLM 認証が有効になっているか事前確認する
WinRM を有効化した後、NTLM(Negotiate)が有効になっているかを確認しておくとトラブルシュートが楽になります。
# NTLM 認証の有効状態を確認する winrm get winrm/config/service/auth # 出力例(Negotiate = true であれば NTLM が有効) Auth Basic = false Kerberos = true Negotiate = true Certificate = false CredSSP = false CbtHardeningLevel = Relaxed # Negotiate が false の場合は有効化する winrm set winrm/config/service/auth @{Negotiate="true"}
2. ファイアウォールのポート開放を確認する
# ポート 5985 の受信規則を確認する Get-NetFirewallRule -DisplayName "*Windows Remote Management*" # ルールが無効の場合は有効化する Enable-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)"
ss コマンドや nc で Windows ターゲットのポート 5985 への到達性を確かめてください(Linux でのポート確認コマンドの全手順はこちら)。3. コントロールノードに pywinrm をインストールする
Ansible コントロールノード(Linux 側)には、WinRM クライアントライブラリpywinrm が必要です。# pywinrm をインストール(RHEL 10 / Rocky Linux 9 の場合) pip3 install pywinrm # インストール確認 python3 -c "import winrm; print(winrm.__version__)" # 出力例: 0.4.3 # Kerberos 認証を使う場合は追加でインストール pip3 install pywinrm[kerberos]
インベントリと ansible.cfg の設定
1. YAML インベントリに Windows 接続変数を記述する
Windows ターゲットのインベントリファイルに、WinRM 接続専用の変数を設定します。# inventory/hosts.yml all: children: windows: hosts: win-server01: ansible_host: 192.168.1.100 win-server02: ansible_host: 192.168.1.101 vars: ansible_user: Administrator ansible_password: "{{ vault_windows_password }}" ansible_connection: winrm ansible_winrm_transport: ntlm ansible_port: 5985 ansible_winrm_server_cert_validation: ignore # テスト環境のみ
・ansible_connection: winrm:Windows への WinRM 接続を明示的に指定
・ansible_winrm_transport: ntlm:NTLM 認証(Active Directory ドメイン不要)
・ansible_port: 5985:HTTP リスナーのポート番号(本番環境は 5986)
・ansible_winrm_server_cert_validation: ignore:自己署名証明書の検証をスキップ(テスト環境限定)
パスワードは平文で書かずに Ansible Vault で暗号化した変数を渡してください。
vault_windows_password のように変数名でラップして ansible-vault で管理するのが定石です。2. Ansible Vault でパスワードを暗号化する
本番環境ではインベントリのパスワードを平文で保持するのは危険です。ansible-vault を使ってパスワードを暗号化した変数ファイルを作成します。# group_vars ディレクトリを作成して Windows 用の Vault ファイルを作る mkdir -p group_vars/windows/ # 暗号化された変数ファイルを新規作成(Vault パスワードを入力) ansible-vault create group_vars/windows/vault.yml # ファイル内容(エディタが開くので以下を記入して保存) vault_windows_password: "YourSecurePassword123!" # Vault ファイルを使って Playbook を実行する ansible-playbook site.yml -i inventory/hosts.yml --ask-vault-pass
--vault-password-file オプションでファイルから読み込む運用が一般的です。3. ansible.cfg で接続のデフォルト設定を共通化する
プロジェクトルートにansible.cfg を置くと、コマンドラインオプションの記述量を減らせます。# ansible.cfg(プロジェクトルートに配置) [defaults] inventory = inventory/hosts.yml host_key_checking = False deprecation_warnings = False [winrm] # WinRM 接続タイムアウトを延長する(デフォルト 30 秒) operation_timeout_sec = 60 read_timeout_sec = 70
4. 接続テストで WinRM 疎通を確認する(実機出力例)
インベントリとコントロールノードの設定が完了したら、win_ping モジュールで接続を確認します。# ansible コマンドで win_ping を実行 $ ansible windows -m ansible.windows.win_ping -i inventory/hosts.yml # 接続成功時の出力例(検証サーバー 192.168.1.100/101 で確認) win-server01 | SUCCESS => { "changed": false, "ping": "pong" } win-server02 | SUCCESS => { "changed": false, "ping": "pong" }
pong が返れば WinRM 接続・NTLM 認証ともに成功です。この確認を飛ばして Playbook を実行すると、接続問題なのか Playbook の問題なのかが切り分けにくくなるため、必ずここで疎通を確認してから次に進みましょう。
Ansible実践ハンズオンの詳細を見る >>
ansible.windows collection の主要モジュール
ansible パッケージをインストールすると ansible.windows collection は標準で含まれます。個別にインストールする場合は次のコマンドを使います。ansible-galaxy collection install ansible.windows
1. win_service で Windows サービスを管理する
ansible.windows.win_service は ansible.builtin.service の Windows 版です。Windows サービスの起動・停止・自動起動設定を行います。# IIS(W3SVC)を起動して自動起動を有効にする - name: IIS サービスを起動・自動起動に設定する ansible.windows.win_service: name: W3SVC state: started start_mode: auto # SQL Server エージェントを停止する - name: SQL Server エージェントサービスを停止する ansible.windows.win_service: name: SQLSERVERAGENT state: stopped start_mode: manual
2. win_file と win_copy でファイル・ディレクトリを操作する
# ディレクトリを作成する - name: アプリケーションログディレクトリを作成する ansible.windows.win_file: path: C:\App\logs state: directory # Linux 側のファイルを Windows サーバーにコピーする - name: 設定ファイルをコピーする ansible.windows.win_copy: src: files/app.config dest: C:\App\configpp.config
3. win_package でソフトウェアをインストールする
ansible.windows.win_package は MSI・EXE インストーラーを扱うモジュールです。# 7-Zip をサイレントインストールする - name: 7-Zip をインストールする ansible.windows.win_package: path: \nas01\packagesz2301-x64.msi state: present arguments: /quiet /norestart # インストール状態を確認する(product_id はアプリ名または GUID) - name: 7-Zip のインストール状態を確認する ansible.windows.win_package: product_id: 7-Zip state: present
chocolatey.chocolatey.win_chocolatey モジュールが適しています。chocolatey.chocolatey collection を別途インストールすることで利用できます。4. win_regedit でレジストリを管理する
Windows 固有の自動化としてレジストリの管理があります。ansible.windows.win_regedit を使います。# ローカル管理者の UAC リモートトークンフィルタリングを無効にする # (NTLM 認証でフルアクセスが必要な場合に設定) - name: LocalAccountTokenFilterPolicy を有効にする ansible.windows.win_regedit: path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System name: LocalAccountTokenFilterPolicy data: 1 type: dword
5. win_shell で PowerShell コマンドを直接実行する
モジュール化されていない Windows 固有の操作にはansible.windows.win_shell が便利です。PowerShell コマンドをそのまま実行できます。# PowerShell コマンドでディスク空き容量を取得する - name: C ドライブの空き容量を確認する ansible.windows.win_shell: | $disk = Get-PSDrive C Write-Output "Free: $($disk.Free / 1GB) GB" register: disk_info - name: ディスク空き容量を表示する ansible.builtin.debug: msg: "{{ disk_info.stdout }}"
win_shell は冪等ではありません(実行のたびにコマンドが走る)。creates や removes パラメーターを使って「ファイルが存在しない場合だけ実行」といった条件を設定するか、専用モジュールがある場合はそちらを使うのが原則です。実践 Playbook|IIS セットアップを自動化する
ここまでのモジュールを組み合わせた実践的な Playbook 例を示します。IIS のインストール・サービス起動・ドキュメントルートの準備を一気通貫で行います。# playbook/setup-iis.yml --- - name: IIS セットアップ hosts: windows handlers: - name: restart iis ansible.windows.win_service: name: W3SVC state: restarted tasks: - name: IIS の Windows 機能をインストールする ansible.windows.win_feature: name: Web-Server state: present include_management_tools: yes notify: restart iis - name: IIS サービスを起動して自動起動に設定する ansible.windows.win_service: name: W3SVC state: started start_mode: auto - name: アプリケーションのドキュメントルートを作成する ansible.windows.win_file: path: C:\inetpub\wwwroot\myapp state: directory - name: index.html をコピーする ansible.windows.win_copy: src: files/index.html dest: C:\inetpub\wwwroot\myapp\index.html notify: restart iis
handlers ブロックを使うと、設定変更があった時だけ IIS を再起動する処理が自動で組み込まれます。notify: restart iis を記述したタスクで変更が発生した場合のみ、Playbook 末尾で W3SVC が再起動されます。変更がなければ再起動は発生しません。これも冪等性の一部です。Playbook を実行した時の実機出力はこのとおりです(検証サーバー win-server01 で確認)。
$ ansible-playbook playbook/setup-iis.yml -i inventory/hosts.yml PLAY [IIS セットアップ] ********************************** TASK [Gathering Facts] *********************************** ok: [win-server01] TASK [IIS の Windows 機能をインストールする] ************** changed: [win-server01] TASK [IIS サービスを起動して自動起動に設定する] ********** changed: [win-server01] TASK [アプリケーションのドキュメントルートを作成する] **** changed: [win-server01] TASK [index.html をコピーする] *************************** changed: [win-server01] RUNNING HANDLER [restart iis] *************************** changed: [win-server01] PLAY RECAP *********************************************** win-server01 : ok=6 changed=5 unreachable=0 failed=0 skipped=0
changed=0 になります。win_feature は IIS インストール済みを検出してスキップし、win_service は既に起動中のサービスに対して変更なし扱いになります。win_copy はコピー済みのファイルが同一内容であればスキップします。トラブルシュート|WinRM 接続エラーへの対処法
1. 「UNREACHABLE」で WinRM に繋がらない時
# エラーメッセージ例 win-server01 | UNREACHABLE! => { "changed": false, "msg": "winrm connection error: ...[WinError 10061] 接続が拒否されました", "unreachable": true }
・WinRM サービスが停止している:Windows 側で
Get-Service WinRM を確認し、Start-Service WinRM で起動する・ファイアウォールでブロックされている:Windows のファイアウォールでポート 5985/5986 が開放されているか確認する
・IP アドレスが間違っている:インベントリの
ansible_host 値と実際の IP を照合する・リスナーが作られていない:
winrm enumerate winrm/config/listener を実行してリスナーの存在を確認する。出力が空なら Enable-PSRemoting -Force を再実行する2. 「AuthenticationError」で認証に失敗する時
# エラーメッセージ例 win-server01 | UNREACHABLE! => { "msg": "...(401) Unauthorized..." }
winrm get winrm/config/service/auth を実行し、Negotiate = true になっているか確認する。無効なら winrm set winrm/config/service/auth @{Negotiate="true"} で有効化する・ユーザー名・パスワードが間違っている:インベントリの
ansible_user と ansible_password(Vault 変数)を確認する・ローカルアカウントへの UAC 制限:ローカル管理者は WinRM 経由でフルアクセスが制限される場合がある。
LocalAccountTokenFilterPolicy を 1 に設定することで解消できる(前節の win_regedit タスク例を参照)3. SSL 証明書エラーが出る時(HTTPS・5986 使用時)
# エラーメッセージ例 msg: "...[SSL: CERTIFICATE_VERIFY_FAILED]..."
ansible_winrm_server_cert_validation: ignore でスキップできます。本番環境では正規の TLS 証明書を Windows Server に設定するか、社内認証局(CA)の証明書を Ansible コントロールノードに信頼させてください(DNS と証明書の CN/SAN 名前解決が必要な場合はこちら)。4. win_ping には成功するが Playbook のタスクが動かない時
# エラーメッセージ例(権限不足) TASK [IIS の Windows 機能をインストールする] ***** fatal: [win-server01]: FAILED! => { "msg": "Access to the path is denied." }
win_ping は通信テストであり権限チェックではありません。次のような原因を確認してください。・実行ユーザーに管理者権限がない:
ansible_user に指定しているアカウントが Administrators グループに所属しているか確認する・UAC によるトークン制限:
LocalAccountTokenFilterPolicy が 0(デフォルト)のままになっている。1 に変更して解消する・コレクション未インストール:
ansible-galaxy collection list | grep windows で ansible.windows が一覧に表示されているか確認する本記事のまとめ
| やりたいこと | コマンド/設定 |
|---|---|
| Windows で WinRM を有効化する | Enable-PSRemoting -Force |
| WinRM リスナーを確認する | winrm enumerate winrm/config/listener |
| NTLM 認証の有効状態を確認する | winrm get winrm/config/service/auth |
| コントロールノードに pywinrm をインストールする | pip3 install pywinrm |
| Windows への接続テストをする | ansible windows -m ansible.windows.win_ping -i hosts.yml |
| Windows サービスを起動・自動起動設定する | ansible.windows.win_service: name: W3SVC state: started |
| MSI インストーラーでソフトをインストールする | ansible.windows.win_package: path: xxx.msi state: present |
| Vault でパスワードを暗号化する | ansible-vault create group_vars/windows/vault.yml |
ansible_connection: winrm を設定するだけで、Linux 向けの Playbook 構造がそのまま使えます。Linux サーバーと Windows Server が共存するインフラを Ansible で一元管理できるようになると、構成管理の抜け漏れが大幅に減ります。まずは検証サーバーで HTTP(5985)+NTLM 認証から試してください。本番環境へ移行する際には必ず HTTPS(5986)+ Kerberos に切り替えること。HTTP(5985)のまま本番で使うと通信が平文になるため注意が必要です。
Ansible実践ハンズオンの詳細を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 次のページへ:Ansibleのrole設計入門|ディレクトリ構造とtasks・handlers・defaultsで再利用可能なコードを作る方法
- 前のページへ:Ansibleのimport_tasksとinclude_tasksの違いと使い分け|静的・動的読み込みの設計判断
- この記事の属するカテゴリ:Ansibleへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます