diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5d5cc3ccac..482e8a9ec1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -264,6 +264,7 @@ Ansible Changes By Release
- windows:
* win_disk_image
* win_dns_client
+ * win_domain
* win_domain_controller
* win_domain_membership
* win_find
diff --git a/docs/docsite/rst/roadmap/ROADMAP_2_3.rst b/docs/docsite/rst/roadmap/ROADMAP_2_3.rst
index 9fafa38bbb..11ebb59a87 100644
--- a/docs/docsite/rst/roadmap/ROADMAP_2_3.rst
+++ b/docs/docsite/rst/roadmap/ROADMAP_2_3.rst
@@ -50,16 +50,16 @@ Target: February/March 2017
- **Windows modules** (nitzmahone)
- - win_domain module
- - win_domain_membership module
- - win_domain_controller module
- - win_dns_client module
+ - win_domain module **(done)**
+ - win_domain_membership module **(done)**
+ - win_domain_controller module **(done)**
+ - win_dns_client module **(done)**
- win_wait_for module
- - win_disk_image module
- - Updates to win_chocolatey, adopt to core (stretch)
- - Updates/rewrite to win_unzip, adopt to core (stretch)
- - Updates to win_updates, adopt to core (stretch)
- - Updates to win_package, adopt to core (+ deprecate win_msi)
+ - win_disk_image module **(done)**
+ - Updates to win_chocolatey, adopt to core (stretch) **(bump to 2.4)**
+ - Updates/rewrite to win_unzip, adopt to core (stretch) **(bump to 2.4)**
+ - Updates to win_updates, adopt to core (stretch) **(bump to 2.4)**
+ - Updates to win_package, adopt to core (+ deprecate win_msi) (stretch) **(bump to 2.4)**
- **Azure modules** (nitzmahone/mattclay)
diff --git a/lib/ansible/modules/windows/win_domain.ps1 b/lib/ansible/modules/windows/win_domain.ps1
new file mode 100644
index 0000000000..144f3e6f77
--- /dev/null
+++ b/lib/ansible/modules/windows/win_domain.ps1
@@ -0,0 +1,82 @@
+#!powershell
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+# WANT_JSON
+# POWERSHELL_COMMON
+
+Set-StrictMode -Version 2
+$ErrorActionPreference = "Stop"
+
+# FUTURE: consider action wrapper to manage reboots and credential changes
+
+Function Ensure-Prereqs {
+ $gwf = Get-WindowsFeature AD-Domain-Services
+ If($gwf.InstallState -ne "Installed") {
+ $result.changed = $true
+
+ If($check_mode) {
+ Exit-Json $result
+ }
+ $awf = Add-WindowsFeature AD-Domain-Services
+ # FUTURE: check if reboot necessary
+ }
+}
+
+$parsed_args = Parse-Args $args -supports_check_mode $true
+$check_mode = Get-AnsibleParam $parsed_args "_ansible_check_mode" -default $false
+$forest_root_dns_domain = Get-AnsibleParam $parsed_args "forest_root_dns_domain" -failifempty $true
+$safe_mode_admin_password = Get-AnsibleParam $parsed_args "safe_mode_password" -failifempty $true
+
+$forest = $null
+
+# FUTURE: support down to Server 2012?
+If([System.Environment]::OSVersion.Version -lt [Version]"6.3.9600.0") {
+ Fail-Json -message "win_domain requires Windows Server 2012R2 or higher"
+}
+
+$result = @{changed=$false; reboot_required=$false}
+
+# FUTURE: any sane way to do the detection under check-mode *without* installing the feature?
+
+Ensure-Prereqs
+
+Try {
+ $forest = Get-ADForest $forest_root_dns_domain -ErrorAction SilentlyContinue
+}
+Catch { }
+
+If(-not $forest) {
+ $result.changed = $true
+
+ If(-not $check_mode) {
+ $sm_cred = ConvertTo-SecureString $safe_mode_admin_password -AsPlainText -Force
+
+ $install_forest_args = @{
+ DomainName=$forest_root_dns_domain;
+ SafeModeAdministratorPassword=$sm_cred;
+ Confirm=$false;
+ SkipPreChecks=$true;
+ InstallDNS=$true;
+ NoRebootOnCompletion=$true;
+ }
+
+ $iaf = Install-ADDSForest @install_forest_args
+
+ $result.reboot_required = $iaf.RebootRequired
+ }
+}
+
+Exit-Json $result
diff --git a/lib/ansible/modules/windows/win_domain.py b/lib/ansible/modules/windows/win_domain.py
new file mode 100644
index 0000000000..1aafb388e5
--- /dev/null
+++ b/lib/ansible/modules/windows/win_domain.py
@@ -0,0 +1,60 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# (c) 2017, Red Hat, Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible. If not, see .
+
+ANSIBLE_METADATA = {'status': ['preview'],
+ 'supported_by': 'core',
+ 'version': '1.0'}
+
+DOCUMENTATION='''
+module: win_domain
+short_description: Ensures the existence of a Windows domain.
+version_added: 2.3
+description:
+ - Ensure that the domain named by C(dns_domain_name) exists and is reachable. If the domain is not reachable, the domain is created in a new forest
+ on the target Windows Server 2012R2+ host. This module may require subsequent use of the M(win_reboot) action if changes are made.
+options:
+ dns_domain_name:
+ description:
+ - the DNS name of the domain which should exist and be reachable or reside on the target Windows host
+ required: true
+ safe_mode_password:
+ description:
+ - safe mode password for the domain controller
+ required: true
+author:
+ - Matt Davis (@nitzmahone)
+'''
+
+RETURN='''
+reboot_required:
+ description: True if changes were made that require a reboot.
+ returned: always
+ type: boolean
+ sample: true
+
+'''
+
+EXAMPLES=r'''
+# ensure the named domain is reachable from the target host; if not, create the domain in a new forest residing on the target host
+- win_domain_controller:
+ dns_domain_name: ansible.vagrant
+ safe_mode_password: password123!
+
+'''