Ansible Lesson 27 of 42

Ansible for Windows, In Depth: WinRM, Kerberos, ansible.windows, community.windows & win_dsc

Linux engineers often inherit Windows fleets they did not ask for: a few hundred file servers, a forest of domain controllers, IIS hosts, SQL boxes, and the inevitable jump servers. The good news is that Ansible — yes, the same Ansible you use for Linux — drives Windows extremely well. The bad news is that getting from “I can SSH to my Linux box” to “I can run a playbook against a domain-joined Windows Server 2022 with Kerberos auth and CredSSP delegation” involves real concepts: WinRM as the wire protocol, Kerberos as the identity layer, PowerShell as the execution engine, and DSC as the optional idempotence backend.

This lesson covers all of it the way EX374 and senior Windows-on-Ansible interviews actually grade it: WinRM listeners and authentication mechanisms, Kerberos vs NTLM vs Basic, the ansible.windows and community.windows module families, win_dsc as a generic bridge to any DSC resource, hardening WinRM-over-HTTPS with proper certificates, and patterns for credential management (gMSA, become, runas) on Windows from a Linux control node.

Learning Objectives

By the end you will be able to:

Prerequisites

Mental Model: How Ansible Talks to Windows

Five concepts unlock everything else.

1. WinRM is “SSH for Windows” — but it’s HTTP

WinRM (Windows Remote Management) is Microsoft’s implementation of WS-Management. From Ansible’s perspective it serves the same role as SSH: a remote shell, file transfer, and a stable transport for executing modules. But it is HTTP under the hood — listening on TCP/5985 (HTTP) or TCP/5986 (HTTPS) — and it speaks SOAP-over-HTTP to a Windows server’s WSMan listener. The control node uses the Python pywinrm library to speak this protocol.

2. Authentication is the hard part — pick once, configure forever

WinRM supports five auth mechanisms: Basic (cleartext password, dev-only), NTLM (works for local accounts and workgroup machines), Kerberos (the only sane choice for domain-joined fleets), CredSSP (required for the “double-hop” problem when your playbook needs to access a fileshare or another server from inside a target host), and Certificate (mTLS with a client cert, useful for fully unattended automation). Pick one per inventory group and configure it consistently — mixing auth modes per host is the #1 cause of “it worked yesterday” outages.

3. PowerShell is the execution engine — modules ship as .ps1

When you run ansible win01 -m ansible.windows.win_service -a "name=Spooler state=stopped", Ansible serializes a small bootstrap PowerShell script, ships it via WinRM, and executes it inside powershell.exe on the target. Each Windows module is a .ps1 file that returns JSON (just like Linux modules return JSON from Python). This is why ansible_python_interpreter doesn’t matter on Windows — the target doesn’t need Python; it needs PowerShell 5.1 or 7.x.

4. win_dsc is the universal idempotence escape hatch

Microsoft DSC (Desired State Configuration) ships with hundreds of resources covering everything from IIS to SQL Server to Active Directory. Rather than write an Ansible module for each of these, the ansible.windows.win_dsc module wraps any DSC resource as an Ansible task. If something is missing from ansible.windows or community.windows, it is almost certainly available as a DSC resource — and win_dsc brings it into your playbook with full idempotence and check-mode support.

5. The Linux control node never installs anything on Windows

Unlike Group Policy or SCCM, Ansible doesn’t deploy an agent on Windows. The only requirement on the target is that WinRM is configured and PowerShell 5.1+ is present (every supported Windows Server has both out of the box). This means you can manage 5,000 Windows servers from a single RHEL VM with no agent fleet to maintain — but it also means every authentication problem is a configuration problem on the target’s WinRM, not an “agent not phoning home” problem.

Setting Up the Linux Control Node

The control node needs three Python libraries beyond Ansible itself:

# Install ansible-core and Windows-specific dependencies
python3 -m pip install --user 'ansible-core>=2.16' 'pywinrm[kerberos]' 'pykrb5'

# Install the two Windows collections
ansible-galaxy collection install ansible.windows community.windows

pywinrm is the Python WinRM client. The [kerberos] extra pulls in pykrb5 and the GSSAPI bindings needed to do Kerberos auth. On RHEL 9 you also need krb5-workstation and krb5-devel for the system Kerberos client.

# RHEL 9 / Rocky / Alma
sudo dnf install -y krb5-workstation krb5-devel python3-devel gcc

# Ubuntu 22.04
sudo apt-get install -y krb5-user libkrb5-dev python3-dev gcc

If you plan to use Kerberos auth (you should, for domain-joined targets) edit /etc/krb5.conf and add your AD realm:

[libdefaults]
default_realm = CORP.EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = true

[realms]
CORP.EXAMPLE.COM = {
    kdc = dc01.corp.example.com
    admin_server = dc01.corp.example.com
}

[domain_realm]
.corp.example.com = CORP.EXAMPLE.COM
corp.example.com = CORP.EXAMPLE.COM

Test the Kerberos config with kinit administrator@CORP.EXAMPLE.COM — if you get a TGT back without errors, your control node can talk to AD.

Setting Up a Windows Target — WinRM-over-HTTPS

The default WinRM listener (HTTP/5985) accepts only NTLM/Kerberos and is acceptable for domain-joined hosts behind a firewall. For everything else, configure HTTPS/5986 with a real certificate.

Option A: Quick start with self-signed (lab only)

Microsoft maintains a ConfigureRemotingForAnsible.ps1 script that creates a self-signed cert and an HTTPS listener:

# Run on the Windows target, as Administrator
$url = "https://raw.githubusercontent.com/ansible/ansible-documentation/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$file = "$env:TEMP\ConfigureRemotingForAnsible.ps1"
Invoke-WebRequest -Uri $url -OutFile $file
powershell.exe -ExecutionPolicy ByPass -File $file -CertValidityDays 3650 -ForceNewSSLCert -EnableCredSSP

This sets up WinRM on 5986 with a self-signed cert. Adequate for a lab, never for production — the control node will have to set ansible_winrm_server_cert_validation: ignore, which defeats the purpose of HTTPS.

Option B: Production-grade with a real certificate

In production, use a certificate issued by your enterprise CA (or ACME via win-acme). The cert’s Subject CN or SAN must match the FQDN your inventory uses.

# On the target, after you've imported a real cert into LocalMachine\My
$thumbprint = (Get-ChildItem Cert:\LocalMachine\My |
    Where-Object {$_.Subject -like "*CN=win01.corp.example.com*"}).Thumbprint

# Create the HTTPS listener
winrm create winrm/config/Listener?Address=*+Transport=HTTPS `
    "@{Hostname=`"win01.corp.example.com`";CertificateThumbprint=`"$thumbprint`"}"

# Disable HTTP listener
winrm delete winrm/config/Listener?Address=*+Transport=HTTP

# Disable unencrypted (defense-in-depth)
winrm set winrm/config/service '@{AllowUnencrypted="false"}'

# Open Windows Firewall for 5986
New-NetFirewallRule -DisplayName "WinRM HTTPS" -Direction Inbound -Protocol TCP `
    -LocalPort 5986 -Action Allow -RemoteAddress 10.0.0.0/8

The -RemoteAddress scoping is critical — only allow your control nodes’ subnet, never 0.0.0.0/0.

Inventory & Connection Variables

A Windows-only inventory:

# inventories/prod/hosts.yml
all:
  children:
    windows_servers:
      hosts:
        win01.corp.example.com:
        win02.corp.example.com:
        win03.corp.example.com:
      vars:
        ansible_connection: winrm
        ansible_port: 5986
        ansible_winrm_transport: kerberos
        ansible_winrm_scheme: https
        ansible_winrm_server_cert_validation: validate
        ansible_user: "ansible-svc@CORP.EXAMPLE.COM"

Note ansible_user uses UPN format (user@REALM) for Kerberos. NTLM would use DOMAIN\user.

If you must use NTLM (workgroup hosts, no AD), it looks like:

ansible_winrm_transport: ntlm
ansible_user: "Administrator"
ansible_password: "{{ vault_admin_password }}"

The ansible.windows Collection — Module-by-Module

ansible.windows is the supported core Windows collection. It covers ~50 modules. The most-used ones, grouped by purpose:

File and template management

Module Purpose Key parameters
win_copy Copy files from controller to Windows src, dest, force, backup
win_file Manage paths, dirs, attributes path, state (file/directory/absent/touch)
win_template Render Jinja2 templates to Windows src, dest, backup, newline_sequence
win_acl NTFS / registry / share ACLs path, user, rights, type, state
win_owner Take ownership of a file/dir path, user, recurse
win_share Manage SMB shares name, path, full, read, state

win_template defaults to newline_sequence: '\r\n' (Windows line endings) — leave that alone unless you’re rendering a file that must have Unix endings.

Services and Scheduled Tasks

Module Purpose Key parameters
win_service Manage Windows services name, state, start_mode, username, password
win_service_info Read service config (gather facts) name (optional, returns all if omitted)
win_scheduled_task (community) Manage scheduled tasks name, actions, triggers, username, state
- name: Ensure print spooler is disabled (CIS hardening)
  ansible.windows.win_service:
    name: Spooler
    state: stopped
    start_mode: disabled

Packages and Features

Module Purpose Key parameters
win_feature Install Windows roles/features name, state, include_management_tools
win_package Install MSI/EXE installers path, product_id, state, arguments
win_chocolatey (community) Chocolatey package manager name, state, version, source
win_psmodule (community) PowerShell Gallery modules name, state, repository
win_updates Windows Update category_names, state, reboot
- name: Install IIS with management tools
  ansible.windows.win_feature:
    name:
      - Web-Server
      - Web-Mgmt-Tools
      - Web-Asp-Net45
    state: present
    include_management_tools: true
  register: iis_install

- name: Reboot if required
  ansible.windows.win_reboot:
  when: iis_install.reboot_required

Users, Groups, and Local Security

Module Purpose Key parameters
win_user Local user accounts name, password, state, groups, password_never_expires
win_group Local groups name, description, state
win_group_membership Add/remove members in a group name, members, state
win_user_right Local user rights (sec policy) name (e.g. SeServiceLogonRight), users, action
win_security_policy Local security policy editor section, key, value

Registry, Environment, and System Tweaks

Module Purpose Key parameters
win_regedit Manage registry keys/values path, name, data, type, state
win_environment Environment variables name, value, level (machine/user)
win_path Manage PATH entries elements, state, scope
win_hosts Manage hosts file state, ip_address, canonical_name, aliases
win_dns_client DNS client settings adapter_names, dns_servers, log_path
- name: Disable SMBv1 (CVE remediation)
  ansible.windows.win_regedit:
    path: HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
    name: SMB1
    data: 0
    type: dword
    state: present

Command Execution

Module Purpose Key parameters
win_command Run a single .exe (no shell parsing) cmd (or free-form), chdir, creates, removes
win_shell Run via PowerShell (pipes, redirection) cmd, executable, chdir, creates
win_powershell First-class PowerShell with structured I/O script, parameters, executable_type
win_dsc Run any DSC resource resource_name, plus DSC resource params

win_powershell (added in ansible.windows 1.5+) is the modern way to run PowerShell — it returns structured output, host_out, error, verbose, etc., separately:

- name: Get top 5 processes by working set
  ansible.windows.win_powershell:
    script: |
      param([int]$Top = 5)
      Get-Process | Sort-Object -Property WS -Descending |
        Select-Object -First $Top Name, Id, WS |
        ConvertTo-Json
    parameters:
      Top: 10
  register: procs

- debug:
    var: procs.output

The community.windows Collection — Higher-level Modules

community.windows extends ansible.windows with hundreds of modules for IIS, AD, Hyper-V, Chocolatey, scheduled tasks, certificate management, DSC, and more. The most-used ones:

Module Purpose
win_scheduled_task Create/update scheduled tasks (most-used module in this collection)
win_iis_website, win_iis_webbinding, win_iis_webapplication, win_iis_webapppool, win_iis_virtualdirectory Full IIS lifecycle
win_chocolatey, win_chocolatey_source, win_chocolatey_config Chocolatey package management
win_domain, win_domain_controller, win_domain_user, win_domain_group, win_domain_membership, win_domain_object_info, win_domain_ou Active Directory
win_certificate_store, win_certificate_info Certificate store management
win_xml, win_lineinfile, win_inifile Text-file manipulation
win_hyperv_* Hyper-V VM lifecycle (less common since Azure took over)
win_firewall, win_firewall_rule Windows Firewall config
win_pssession_configuration Custom PowerShell session configurations
- name: Create a daily backup scheduled task
  community.windows.win_scheduled_task:
    name: "Daily DB Backup"
    description: "Backs up the local SQL DB to a fileshare"
    actions:
      - path: powershell.exe
        arguments: "-NoProfile -File C:\\scripts\\backup.ps1"
    triggers:
      - type: daily
        start_boundary: "2025-01-01T02:00:00"
    username: "CORP\\sql-backup-svc"
    logon_type: password
    password: "{{ vault_sql_backup_password }}"
    state: present

win_dsc — The Universal Bridge

DSC ships hundreds of community modules: xWebAdministration, xActiveDirectory, SqlServerDsc, NetworkingDsc, ComputerManagementDsc, plus your own custom DSC resources. ansible.windows.win_dsc lets you call any of them as a regular Ansible task with full idempotence and check-mode support.

- name: Ensure xWebAdministration is installed
  community.windows.win_psmodule:
    name: xWebAdministration
    state: present

- name: Configure an IIS site via DSC
  ansible.windows.win_dsc:
    resource_name: xWebSite
    Name: "Default Web Site"
    PhysicalPath: "C:\\inetpub\\wwwroot"
    State: Started
    BindingInfo:
      - Protocol: https
        Port: 443
        CertificateThumbprint: "{{ iis_cert_thumbprint }}"
        CertificateStoreName: "MY"

The shape of win_dsc is mechanical: resource_name is the DSC resource (capitalization matters), and every other key is a property of that DSC resource. Get-DscResource -Name xWebSite -Syntax on the target will print the full schema.

When win_dsc shows changed: false, it ran DSC’s Test-TargetResource and the resource is in the desired state. When it shows changed: true, it ran Set-TargetResource to converge. This is true idempotence — no “did the task run? maybe?” guessing.

Hands-on Free Lab: WinRM-over-HTTPS with Kerberos

This lab takes you from “fresh Windows Server 2022 evaluation VM” to “production-grade Ansible-managed host” without spending money. Microsoft’s evaluation Windows Server 2022 ISO is free for 180 days.

# On your Linux control node
mkdir -p ~/ansible-windows-lab && cd ~/ansible-windows-lab

# Create inventory
cat > inventory.yml <<'EOF'
all:
  children:
    windows_lab:
      hosts:
        win01.lab.local:
      vars:
        ansible_connection: winrm
        ansible_port: 5985
        ansible_winrm_transport: ntlm  # NTLM for the lab; switch to kerberos after AD setup
        ansible_user: "Administrator"
        ansible_password: "{{ lab_admin_password }}"
        ansible_winrm_server_cert_validation: ignore
EOF

# Create the playbook
cat > site.yml <<'EOF'
---
- hosts: windows_lab
  gather_facts: true
  tasks:

    - name: Install Web Server role with mgmt tools
      ansible.windows.win_feature:
        name:
          - Web-Server
          - Web-Mgmt-Console
          - Web-Asp-Net45
        state: present
        include_management_tools: true
      register: iis

    - name: Reboot if Web Server install requires it
      ansible.windows.win_reboot:
      when: iis.reboot_required

    - name: Render an IIS welcome page from a template
      ansible.windows.win_template:
        src: welcome.html.j2
        dest: 'C:\inetpub\wwwroot\index.html'

    - name: Open firewall for HTTP
      community.windows.win_firewall_rule:
        name: "HTTP-In"
        localport: 80
        action: allow
        direction: in
        protocol: tcp
        state: present
        enabled: true

    - name: Disable SMBv1 (defense-in-depth)
      ansible.windows.win_regedit:
        path: HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
        name: SMB1
        data: 0
        type: dword
        state: present

    - name: Create a service account for app deployments
      ansible.windows.win_user:
        name: app-deploy-svc
        password: "{{ vault_deploy_svc_password }}"
        password_never_expires: true
        state: present
        groups:
          - Administrators

    - name: Grant the deploy account 'log on as service' right
      ansible.windows.win_user_right:
        name: SeServiceLogonRight
        users:
          - app-deploy-svc
        action: add
EOF

# Create the template
cat > welcome.html.j2 <<'EOF'
<!DOCTYPE html>
<html>
<head><title>{{ ansible_hostname }}</title></head>
<body>
  <h1>Welcome to {{ ansible_hostname }}</h1>
  <p>OS: {{ ansible_distribution }} {{ ansible_distribution_version }}</p>
  <p>Provisioned by Ansible at {{ ansible_date_time.iso8601 }}</p>
</body>
</html>
EOF

# Run the playbook
ansible-playbook -i inventory.yml site.yml \
  -e "lab_admin_password=YourLabPassw0rd! vault_deploy_svc_password=YourDeployPassw0rd!"

# Verify
curl -s http://win01.lab.local/ | grep "Welcome"

After this works, switch to Kerberos auth:

  1. Promote win01 to a Domain Controller (or join an existing AD).
  2. Create a service account ansible-svc@LAB.LOCAL and grant it admin on the target.
  3. Update inventory:
ansible_winrm_transport: kerberos
ansible_user: "ansible-svc@LAB.LOCAL"
# remove ansible_password — kinit handles credentials
  1. On the control node: kinit ansible-svc@LAB.LOCAL
  2. Re-run the playbook — same playbook, no password in inventory, ticket-based auth.

Common Mistakes & Troubleshooting

1. “WinRM authentication failed” on a domain-joined host with NTLM Group Policy may have disabled NTLM for inbound auth. Switch to Kerberos (the right answer anyway) or check Computer Configuration\Policies\Windows Settings\Security Settings\Local Policies\Security Options\Network security: Restrict NTLM.

2. “Server not found in Kerberos database” Either the host’s SPN is missing or your /etc/krb5.conf realm is wrong. Run setspn -L <hostname> on the DC — there must be HTTP/win01.corp.example.com registered. If missing: setspn -A HTTP/win01.corp.example.com win01.

3. “Clock skew too great” Kerberos rejects tickets if client and KDC clocks differ by more than 5 minutes. Run chronyc sources -v (Linux) and w32tm /query /status (Windows) to verify both are syncing to the same NTP source.

4. The “double-hop” problem Your playbook accesses \\fileserver\share from win01 and gets “access denied” even though the user has rights. This is by design — NTLM/Kerberos won’t forward credentials past one hop. Solution: enable CredSSP (ansible_winrm_transport: credssp) which performs delegation, OR use a UNC-aware tool like Copy-Item -ToSession, OR avoid the hop entirely by copying via win_copy (which uses the WinRM session, not the user’s identity).

5. “Certificate verify failed” with HTTPS listener The cert is self-signed or its chain isn’t trusted on the control node. Either set ansible_winrm_server_cert_validation: ignore (lab only), or copy the CA cert to /etc/pki/ca-trust/source/anchors/ and run update-ca-trust.

6. win_updates runs forever win_updates waits for the entire update cycle including reboots and re-runs of pending updates. Set category_names: ['SecurityUpdates'] to scope it, and state: searched to just enumerate without installing.

7. win_dsc says “resource not found” The DSC module isn’t installed on the target. community.windows.win_psmodule: name=xWebAdministration state=present first, then call win_dsc.

Best Practices

Security Notes

Q&A — 14 Questions

Q1. Why does Ansible use WinRM instead of SSH for Windows? Windows ships WinRM out of the box on every Server SKU since 2008 R2. SSH for Windows (OpenSSH on Server 2019+) is supported by Ansible too (ansible_connection: ssh works on Windows), but WinRM has years of operational maturity, deeper Kerberos integration, and richer error semantics for PowerShell-driven modules.

Q2. What is the [kerberos] extra in pywinrm[kerberos]? It pulls in pykrb5 and the GSSAPI Python bindings so the control node can do Kerberos auth. Without it, ansible_winrm_transport: kerberos fails with “kerberos extension not available.”

Q3. Why does kinit work but Ansible still fails with auth errors? Probably an SPN mismatch. Run klist after kinit, then check the service principal — it must be HTTP/<fqdn>@REALM. If the SPN registered in AD is HTTP/<short-hostname> instead, Kerberos rejects the ticket.

Q4. What’s the difference between win_command, win_shell, and win_powershell? win_command runs an executable directly with no shell — no pipes, no redirection (use this for safety). win_shell runs via PowerShell, allowing pipes and redirection. win_powershell is the modern, structured-output equivalent of win_shell — returns separate output, error, verbose, host_out channels.

Q5. Can I manage Windows from a Linux control node without any AD/Kerberos? Yes — use NTLM auth with local accounts. ansible_winrm_transport: ntlm, ansible_user: "Administrator", ansible_password: "...". Works fine for workgroup machines or break-glass scenarios.

Q6. What is CredSSP and when do I need it? CredSSP (Credential Security Support Provider) is a Windows auth mechanism that performs credential delegation. You need it when your playbook on host A needs to authenticate to host B as the original user — e.g., a script that copies from a fileshare. NTLM and Kerberos won’t forward creds past the first hop; CredSSP will.

Q7. Why does win_updates take so long? Because it runs Windows Update synchronously: search, download, install, reboot if required, re-search for pending updates. A fresh Server 2022 with 6 months of pending updates can run for 90+ minutes. Scope it with category_names: ['SecurityUpdates', 'CriticalUpdates'] and consider using a separate WSUS server.

Q8. What does win_dsc give me that the regular Windows modules don’t? Coverage. ansible.windows and community.windows have ~250 modules combined; DSC has thousands. If you need to manage IIS request filtering, SQL Server replication, or AD recycle bin — there’s a DSC resource for it, and win_dsc brings it into Ansible.

Q9. How do gMSAs work with Ansible? gMSAs (group Managed Service Accounts) are AD accounts whose password rotates automatically every 30 days. To use one with Ansible: install the gMSA on the host (Install-ADServiceAccount), grant it admin rights, then set ansible_user: "gmsa-name$@CORP.EXAMPLE.COM" (note the $ suffix) and let Kerberos handle the keytab. No password ever in the vault.

Q10. Should I use SSH on Windows instead of WinRM? For greenfield environments, SSH is a viable choice — Microsoft’s OpenSSH is solid. But the Windows module ecosystem assumes WinRM, and SSH-on-Windows has subtle differences in how environment variables and console encodings work. Stick with WinRM unless you have a strong reason.

Q11. What’s the difference between ansible.windows.win_feature and community.windows.win_chocolatey? win_feature installs Windows roles and features that ship with Windows itself (IIS, AD-DS, Hyper-V, .NET 3.5). win_chocolatey installs third-party software via the Chocolatey package manager (Notepad++, 7-Zip, Git, JDK). Use the right tool for the right thing — don’t try to install IIS via Chocolatey.

Q12. Can I run Ansible on a Windows control node? Officially no — Ansible requires a Unix-like control node. Use WSL2 if you must run from a Windows engineer’s laptop (ansible-core runs fine in WSL2 Ubuntu and can drive Windows targets via WinRM).

Q13. How do I rotate the WinRM listener cert without downtime? Issue the new cert into LocalMachine\My, then winrm set winrm/config/Listener?Address=*+Transport=HTTPS '@{CertificateThumbprint="<new-thumbprint>"}'. WinRM picks up the new cert on the next connection — no service restart needed.

Q14. Why doesn’t my playbook see Windows facts (ansible_distribution, ansible_hostname)? You probably set gather_facts: false at the play level, or the connection is failing before facts run. Set gather_facts: true and verify the auth works with ansible win01 -m ansible.windows.win_ping before debugging fact-related issues.

Quick Check

  1. Which auth transport is the only sane choice for a domain-joined fleet?
  2. What port does WinRM-over-HTTPS listen on by default?
  3. What does ansible.windows.win_dsc do?
  4. How do you grant the SeServiceLogonRight to a local account?
  5. What’s the difference between ansible_user: user@REALM and ansible_user: DOMAIN\user?
  6. Why must clocks be in sync within 5 minutes for Kerberos auth?
  7. Which collection contains win_scheduled_taskansible.windows or community.windows?
  8. What’s the canonical way to check if a win_feature install requires reboot?

Exercise

Build a complete role windows_iis_baseline that:

  1. Installs IIS with management tools (use win_feature).
  2. Installs the xWebAdministration DSC module (use win_psmodule).
  3. Renders a custom applicationHost.config snippet via win_template.
  4. Configures a default site via win_dsc + xWebSite.
  5. Creates a dedicated app pool service account (gMSA preferred, fallback to local user).
  6. Opens the firewall for HTTPS only (drop HTTP).
  7. Includes a validate.yml task list that uses win_uri to confirm the site responds with HTTP 200.

Test it with both NTLM (workgroup target) and Kerberos (domain-joined target) and confirm both code paths work without changing the role.

Cert Mapping

Glossary

Next Steps

You can now bring Windows fleets into the same playbook ecosystem as your Linux fleet, with proper Kerberos auth and DSC-backed idempotence. The next lesson covers Ansible for Kubernetes — the kubernetes.core collection, k8s module, manifest templating, Helm chart lifecycle, and the patterns that let you treat clusters as configuration-managed targets rather than imperative scripts.

ansiblewindowswinrmkerberosdscansible-windowscommunity-windowswin-dscwindows-serveractive-directorypowershellkloudvin
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments