Adding module win_domain_computer (#35954)

* Adding module win_domain_computer

This module is a wrapper of powershell *-ADComputer commands.
The main use case is to add non-windows computers to Active Directory
through a bridge windows computer.

* Replace `Set-Attr`

* Fix case insensitive comparisons

* Add omitted parameters in cmdlets

* Enhance module documentation

* Simplify `state` as case insensitive.

* Simplify try catch

* Fix indentation

* Make message errors more descriptive.

* Specify type in boolean parameters

* Keep parameter ingestion together

* Delete superfluous resultobj

* Workaround failing Erroraction

* Add target info in error

* Cosmetic changes

* Fix up Fail-Json to use correct message param
This commit is contained in:
Daniel-Sanchez-Fabregas 2018-05-17 05:06:01 +02:00 committed by Jordan Borean
parent 57c801c34f
commit ee2adb45a8
2 changed files with 279 additions and 0 deletions

View file

@ -0,0 +1,186 @@
#!powershell
#
# Copyright: (c) 2017, AMTEGA - Xunta de Galicia
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#Requires -Module Ansible.ModuleUtils.Legacy
# ------------------------------------------------------------------------------
$ErrorActionPreference = "Stop"
# Preparing result
$result = @{}
$result.changed = $false
# Parameter ingestion
$params = Parse-Args $args -supports_check_mode $true
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
$diff_support = Get-AnsibleParam -obj $params -name "_ansible_diff" -type "bool" -default $false
$name = Get-AnsibleParam -obj $params -name "name" -failifempty $true -resultobj $result
$sam_account_name = Get-AnsibleParam -obj $params -name "sam_account_name" -default "$name$"
If (-not $sam_account_name.EndsWith("$")) {
Fail-Json -obj $result -message "sam_account_name must end in $"
}
$enabled = Get-AnsibleParam -obj $params -name "enabled" -type "bool" -default $true
$description = Get-AnsibleParam -obj $params -name "description" -default ""
$state = Get-AnsibleParam -obj $params -name "state" -ValidateSet "present","absent" -default "present"
If ($state -eq "present") {
$dns_hostname = Get-AnsibleParam -obj $params -name "dns_hostname" -failifempty $true -resultobj $result
$ou = Get-AnsibleParam -obj $params -name "ou" -failifempty $true -resultobj $result
$distinguished_name = "CN=$name,$ou"
$desired_state = @{
name = $name
sam_account_name = $sam_account_name
dns_hostname = $dns_hostname
ou = $ou
distinguished_name = $distinguished_name
description = $description
enabled = $enabled
state = $state
}
} Else {
$desired_state = @{
name = $name
state = $state
}
}
# ------------------------------------------------------------------------------
Function Get-InitialState($desired_state) {
# Test computer exists
$computer = Try {
Get-ADComputer `
-Identity $desired_state.name `
-Properties DistinguishedName,DNSHostName,Enabled,Name,SamAccountName,Description,ObjectClass
} Catch { $null }
If ($computer) {
$initial_state = @{
name = $computer.Name
sam_account_name = $computer.SamAccountName
dns_hostname = $computer.DNSHostName
# Get OU from regexp that removes all characters to the first ","
ou = $computer.DistinguishedName -creplace "^[^,]*,",""
distinguished_name = $computer.DistinguishedName
description = $computer.Description
enabled = $computer.Enabled
state = "present"
}
} Else {
$initial_state = @{
name = $desired_state.name
state = "absent"
}
}
return $initial_state
}
# ------------------------------------------------------------------------------
Function Set-ConstructedState($initial_state, $desired_state) {
Try {
Set-ADComputer `
-Identity $desired_state.name `
-SamAccountName $desired_state.name `
-DNSHostName $desired_state.dns_hostname `
-Enabled $desired_state.enabled `
-Description $desired_state.description `
-WhatIf:$check_mode
} Catch {
Fail-Json -obj $result -message "Failed to set the AD object $($desired_state.name): $($_.Exception.Message)"
}
If ($initial_state.distinguished_name -cne $desired_state.distinguished_name) {
# Move computer to OU
Try {
Get-ADComputer -Identity $desired_state.name |
Move-ADObject `
-TargetPath $desired_state.ou `
-Confirm:$False `
-WhatIf:$check_mode
} Catch {
Fail-Json -obj $result -message "Failed to move the AD object $($desired_state.name) to $($desired_state.ou) OU: $($_.Exception.Message)"
}
}
$result.changed = $true
}
# ------------------------------------------------------------------------------
Function Add-ConstructedState($desired_state) {
Try {
New-ADComputer `
-Name $desired_state.name `
-SamAccountName $desired_state.sam_account_name `
-DNSHostName $desired_state.dns_hostname `
-Path $desired_state.ou `
-Enabled $desired_state.enabled `
-Description $desired_state.description `
-WhatIf:$check_mode
} Catch {
Fail-Json -obj $result -message "Failed to create the AD object $($desired_state.name): $($_.Exception.Message)"
}
$result.changed = $true
}
# ------------------------------------------------------------------------------
Function Remove-ConstructedState($initial_state) {
Try {
Remove-ADComputer `
-Identity $initial_state.name `
-Confirm:$False `
-WhatIf:$check_mode
} Catch {
Fail-Json -obj $result -message "Failed to remove the AD object $($desired_state.name): $($_.Exception.Message)"
}
$result.changed = $true
}
# ------------------------------------------------------------------------------
Function are_hashtables_equal($x, $y) {
# Compare not nested HashTables
Foreach ($key in $x.Keys) {
If (($y.Keys -notcontains $key) -or ($x[$key] -cne $y[$key])) {
Return $false
}
}
foreach ($key in $y.Keys) {
if (($x.Keys -notcontains $key) -or ($x[$key] -cne $y[$key])) {
Return $false
}
}
Return $true
}
# ------------------------------------------------------------------------------
$initial_state = Get-InitialState($desired_state)
If ($desired_state.state -eq "present") {
If ($initial_state.state -eq "present") {
$in_desired_state = are_hashtables_equal $initial_state $desired_state
If (-not $in_desired_state) {
Set-ConstructedState $initial_state $desired_state
}
} Else { # $desired_state.state = "Present" & $initial_state.state = "Absent"
Add-ConstructedState($desired_state)
}
} Else { # $desired_state.state = "Absent"
If ($initial_state.state -eq "present") {
Remove-ConstructedState($initial_state)
}
}
If ($diff_support) {
$diff = @{
before = $initial_state
after = $desired_state
}
$result.diff = $diff
}
Exit-Json -obj $result

View file

@ -0,0 +1,93 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2017, AMTEGA - Xunta de Galicia
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: win_domain_computer
short_description: Manage computers in Active Directory
description:
- Create, read, update and delete computers in Active Directory using a
windows brigde computer to launch New-ADComputer, Get-ADComputer,
Set-ADComputer, Remove-ADComputer and Move-ADObject powershell commands.
options:
name:
description:
- Specifies the name of the object. This parameter sets the Name property
of the Active Directory object. The LDAP display name (ldapDisplayName)
of this property is name.
required: true
sam_account_name:
description:
- Specifies the Security Account Manager (SAM) account name of the
computer. It maximum is 256 characters, 15 is advised for older
operating systems compatibility. The LDAP display name
(ldapDisplayName) for this property is sAMAccountName. If ommitted the
value is the same as C(name).
Note. All computer SAMAccountNames needs to end with a $.
enabled:
description:
- Specifies if an account is enabled. An enabled account requires a
password. This parameter sets the Enabled property for an account
object. This parameter also sets the ADS_UF_ACCOUNTDISABLE flag of the
Active Directory User Account Control (UAC) attribute.
type: bool
default: 'yes'
ou:
description:
- Specifies the X.500 path of the Organizational Unit (OU) or container
where the new object is created. Required when I(state=present).
description:
description:
- Specifies a description of the object. This parameter sets the value
of the Description property for the object. The LDAP display name
(ldapDisplayName) for this property is description.
default: ''
dns_hostname:
description:
- Specifies the fully qualified domain name (FQDN) of the computer. This
parameter sets the DNSHostName property for a computer object. The LDAP
display name for this property is dNSHostName. Required when
I(state=present).
state:
description:
- Specified whether the computer should be C(present) or C(absent) in
Active Directory.
choices:
- present
- absent
default: present
notes:
version_added: 2.6
author: Daniel Sánchez Fábregas (@Daniel-Sanchez-Fabregas)
'''
EXAMPLES = '''
- name: Add linux computer to Active Directory OU using a windows machine
win_domain_computer:
name: one_linux_server.my_org.local
sam_account_name: linux_server
dns_hostname: one_linux_server.my_org.local
ou: "OU=servers,DC=my_org,DC=local"
description: Example of linux server
enabled: yes
state: present
delegate_to: my_windows_bridge.my_org.local
- name: Remove linux computer from Active Directory using a windows machine
win_domain_computer:
name: one_linux_server.my_org.local
state: absent
delegate_to: my_windows_bridge.my_org.local
'''
RETURN = '''
'''