#!powershell # Copyright: (c) 2017, Jordan Borean , and others # 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" $params = Parse-Args -arguments $args -supports_check_mode $true $check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false $diff_mode = Get-AnsibleParam -obj $params -name "_ansible_diff" -type "bool" -default $false $name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true $display_name = Get-AnsibleParam -obj $params -name "display_name" -type "str" $domain_username = Get-AnsibleParam -obj $params -name "domain_username" -type "str" $domain_password = Get-AnsibleParam -obj $params -name "domain_password" -type "str" -failifempty ($domain_username -ne $null) $description = Get-AnsibleParam -obj $params -name "description" -type "str" $category = Get-AnsibleParam -obj $params -name "category" -type "str" -validateset "distribution","security" $scope = Get-AnsibleParam -obj $params -name "scope" -type "str" -validateset "domainlocal","global","universal" $managed_by = Get-AnsibleParam -obj $params -name "managed_by" -type "str" $attributes = Get-AnsibleParam -obj $params -name "attributes" $organizational_unit = Get-AnsibleParam -obj $params -name "organizational_unit" -type "str" -aliases "ou","path" $state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent" $protect = Get-AnsibleParam -obj $params -name "protect" -type "bool" $ignore_protection = Get-AnsibleParam -obj $params -name "ignore_protection" -type "bool" -default $false $domain_server = Get-AnsibleParam -obj $params -name "domain_server" -type "str" $result = @{ changed = $false } if ($diff_mode) { $result.diff = @{} } if (-not (Get-Module -Name ActiveDirectory -ListAvailable)) { Fail-Json $result "win_domain_group requires the ActiveDirectory PS module to be installed" } Import-Module ActiveDirectory $extra_args = @{} if ($domain_username -ne $null) { $domain_password = ConvertTo-SecureString $domain_password -AsPlainText -Force $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $domain_username, $domain_password $extra_args.Credential = $credential } if ($domain_server -ne $null) { $extra_args.Server = $domain_server } try { $group = Get-ADGroup -Identity $name -Properties * @extra_args } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { $group = $null } catch { Fail-Json $result "failed to retrieve initial details for group $($name): $($_.Exception.Message)" } if ($state -eq "absent") { if ($group -ne $null) { if ($group.ProtectedFromAccidentalDeletion -eq $true -and $ignore_protection -eq $true) { $group = $group | Set-ADObject -ProtectedFromAccidentalDeletion $false -WhatIf:$check_mode -PassThru @extra_args } elseif ($group.ProtectedFromAccidentalDeletion -eq $true -and $ignore_protection -eq $false) { Fail-Json $result "cannot delete group $name when ProtectedFromAccidentalDeletion is turned on, run this module with ignore_protection=true to override this" } try { $group | Remove-ADGroup -Confirm:$false -WhatIf:$check_mode @extra_args } catch { Fail-Json $result "failed to remove group $($name): $($_.Exception.Message)" } $result.changed = $true if ($diff_mode) { $result.diff.prepared = "-[$name]" } } } else { # validate that path is an actual path if ($organizational_unit -ne $null) { try { Get-ADObject -Identity $organizational_unit @extra_args | Out-Null } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { Fail-Json $result "the group path $organizational_unit does not exist, please specify a valid LDAP path" } } $diff_text = $null if ($group -ne $null) { # will be overriden later if no change actually occurs $diff_text += "[$name]`n" # change the path of the group if ($organizational_unit -ne $null) { $group_cn = $group.CN $existing_path = $group.DistinguishedName -replace "^CN=$group_cn,",'' if ($existing_path -ne $organizational_unit) { $protection_disabled = $false if ($group.ProtectedFromAccidentalDeletion -eq $true -and $ignore_protection -eq $true) { $group | Set-ADObject -ProtectedFromAccidentalDeletion $false -WhatIf:$check_mode -PassThru @extra_args | Out-Null $protection_disabled = $true } elseif ($group.ProtectedFromAccidentalDeletion -eq $true -and $ignore_protection -eq $false) { Fail-Json $result "cannot move group $name when ProtectedFromAccidentalDeletion is turned on, run this module with ignore_protection=true to override this" } try { $group = $group | Move-ADObject -Targetpath $organizational_unit -WhatIf:$check_mode -PassThru @extra_args } catch { Fail-Json $result "failed to move group from $existing_path to $($organizational_unit): $($_.Exception.Message)" } finally { if ($protection_disabled -eq $true) { $group | Set-ADObject -ProtectedFromAccidentalDeletion $true -WhatIf:$check_mode -PassThru @extra_args | Out-Null } } $result.changed = $true $diff_text += "-DistinguishedName = CN=$group_cn,$existing_path`n+DistinguishedName = CN=$group_cn,$organizational_unit`n" if ($protection_disabled -eq $true) { $group | Set-ADObject -ProtectedFromAccidentalDeletion $true -WhatIf:$check_mode @extra_args | Out-Null } # get the group again once we have moved it $group = Get-ADGroup -Identity $name -Properties * @extra_args } } # change attributes of group $extra_scope_change = $null $run_change = $false $set_args = $extra_args.Clone() if ($scope -ne $null) { if ($group.GroupScope -ne $scope) { # you cannot from from Global to DomainLocal and vice-versa, we # need to change it to Universal and then finally to the target # scope if ($group.GroupScope -eq "global" -and $scope -eq "domainlocal") { $set_args.GroupScope = "Universal" $extra_scope_change = $scope } elseif ($group.GroupScope -eq "domainlocal" -and $scope -eq "global") { $set_args.GroupScope = "Universal" $extra_scope_change = $scope } else { $set_args.GroupScope = $scope } $run_change = $true $diff_text += "-GroupScope = $($group.GroupScope)`n+GroupScope = $scope`n" } } if ($description -ne $null -and $group.Description -cne $description) { $set_args.Description = $description $run_change = $true $diff_text += "-Description = $($group.Description)`n+Description = $description`n" } if ($display_name -ne $null -and $group.DisplayName -cne $display_name) { $set_args.DisplayName = $display_name $run_change = $true $diff_text += "-DisplayName = $($group.DisplayName)`n+DisplayName = $display_name`n" } if ($category -ne $null -and $group.GroupCategory -ne $category) { $set_args.GroupCategory = $category $run_change = $true $diff_text += "-GroupCategory = $($group.GroupCategory)`n+GroupCategory = $category`n" } if ($managed_by -ne $null) { if ($group.ManagedBy -eq $null) { $set_args.ManagedBy = $managed_by $run_change = $true $diff_text += "+ManagedBy = $managed_by`n" } else { try { $managed_by_object = Get-ADGroup -Identity $managed_by @extra_args } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { try { $managed_by_object = Get-ADUser -Identity $managed_by @extra_args } catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] { Fail-Json $result "failed to find managed_by user or group $managed_by to be used for comparison" } } if ($group.ManagedBy -ne $managed_by_object.DistinguishedName) { $set_args.ManagedBy = $managed_by $run_change = $true $diff_text += "-ManagedBy = $($group.ManagedBy)`n+ManagedBy = $($managed_by_object.DistinguishedName)`n" } } } if ($attributes -ne $null) { $add_attributes = @{} $replace_attributes = @{} foreach ($attribute in $attributes.GetEnumerator()) { $attribute_name = $attribute.Name $attribute_value = $attribute.Value $valid_property = [bool]($group.PSobject.Properties.name -eq $attribute_name) if ($valid_property) { $existing_value = $group.$attribute_name if ($existing_value -cne $attribute_value) { $replace_attributes.$attribute_name = $attribute_value $diff_text += "-$attribute_name = $existing_value`n+$attribute_name = $attribute_value`n" } } else { $add_attributes.$attribute_name = $attribute_value $diff_text += "+$attribute_name = $attribute_value`n" } } if ($add_attributes.Count -gt 0) { $set_args.Add = $add_attributes $run_change = $true } if ($replace_attributes.Count -gt 0) { $set_args.Replace = $replace_attributes $run_change = $true } } if ($run_change) { try { $group = $group | Set-ADGroup -WhatIf:$check_mode -PassThru @set_args } catch { Fail-Json $result "failed to change group $($name): $($_.Exception.Message)" } $result.changed = $true if ($extra_scope_change -ne $null) { try { $group = $group | Set-ADGroup -GroupScope $extra_scope_change -WhatIf:$check_mode -PassThru @extra_args } catch { Fail-Json $result "failed to change scope of group $name to $($scope): $($_.Exception.Message)" } } } # make sure our diff text is null if no change occured if ($result.changed -eq $false) { $diff_text = $null } } else { # validate if scope is set if ($scope -eq $null) { Fail-Json $result "scope must be set when state=present and the group doesn't exist" } $diff_text += "+[$name]`n+Scope = $scope`n" $add_args = $extra_args.Clone() $add_args.Name = $name $add_args.GroupScope = $scope if ($description -ne $null) { $add_args.Description = $description $diff_text += "+Description = $description`n" } if ($display_name -ne $null) { $add_args.DisplayName = $display_name $diff_text += "+DisplayName = $display_name`n" } if ($category -ne $null) { $add_args.GroupCategory = $category $diff_text += "+GroupCategory = $category`n" } if ($managed_by -ne $null) { $add_args.ManagedBy = $managed_by $diff_text += "+ManagedBy = $managed_by`n" } if ($attributes -ne $null) { $add_args.OtherAttributes = $attributes foreach ($attribute in $attributes.GetEnumerator()) { $diff_text += "+$($attribute.Name) = $($attribute.Value)`n" } } if ($organizational_unit -ne $null) { $add_args.Path = $organizational_unit $diff_text += "+Path = $organizational_unit`n" } try { $group = New-AdGroup -WhatIf:$check_mode -PassThru @add_args } catch { Fail-Json $result "failed to create group $($name): $($_.Exception.Message)" } $result.changed = $true } # set the protection value if ($protect -ne $null) { if (-not $check_mode) { $group = Get-ADGroup -Identity $name -Properties * @extra_args } $existing_protection_value = $group.ProtectedFromAccidentalDeletion if ($existing_protection_value -eq $null) { $existing_protection_value = $false } if ($existing_protection_value -ne $protect) { $diff_text += @" -ProtectedFromAccidentalDeletion = $existing_protection_value +ProtectedFromAccidentalDeletion = $protect "@ $group | Set-ADObject -ProtectedFromAccidentalDeletion $protect -WhatIf:$check_mode -PassThru @extra_args $result.changed = $true } } if ($diff_mode -and $diff_text -ne $null) { $result.diff.prepared = $diff_text } if (-not $check_mode) { $group = Get-ADGroup -Identity $name -Properties * @extra_args $result.sid = $group.SID.Value $result.description = $group.Description $result.distinguished_name = $group.DistinguishedName $result.display_name = $group.DisplayName $result.name = $group.Name $result.canonical_name = $group.CanonicalName $result.guid = $group.ObjectGUID $result.protected_from_accidental_deletion = $group.ProtectedFromAccidentalDeletion $result.managed_by = $group.ManagedBy $result.group_scope = ($group.GroupScope).ToString() $result.category = ($group.GroupCategory).ToString() if ($attributes -ne $null) { $result.attributes = @{} foreach ($attribute in $attributes.GetEnumerator()) { $attribute_name = $attribute.Name $result.attributes.$attribute_name = $group.$attribute_name } } } } Exit-Json $result