diff --git a/lib/ansible/modules/windows/win_user_right.ps1 b/lib/ansible/modules/windows/win_user_right.ps1 new file mode 100644 index 00000000000..452f7c77dd7 --- /dev/null +++ b/lib/ansible/modules/windows/win_user_right.ps1 @@ -0,0 +1,413 @@ +#!powershell +# This file is part of Ansible + +# Copyright (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#Requires -Module Ansible.ModuleUtils.Legacy.psm1 +$ErrorActionPreference = 'Stop' + +$params = Parse-Args $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 +$users = Get-AnsibleParam -obj $params -name "users" -type "list" -failifempty $true +$action = Get-AnsibleParam -obj $params -name "action" -type "str" -default "set" -validateset "add","remove","set" + +$result = @{ + changed = $false + added = @() + removed = @() +} + +if ($diff_mode) { + $result.diff = @{} +} + +Add-Type -TypeDefinition @" +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Security.Principal; + +namespace Ansible +{ + public class LsaRightHelper : IDisposable + { + // Code modified from https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0 + + enum Access : int + { + POLICY_READ = 0x20006, + POLICY_ALL_ACCESS = 0x00F0FFF, + POLICY_EXECUTE = 0X20801, + POLICY_WRITE = 0X207F8 + } + + IntPtr lsaHandle; + + const string LSA_DLL = "advapi32.dll"; + const CharSet DEFAULT_CHAR_SET = CharSet.Unicode; + + const uint STATUS_NO_MORE_ENTRIES = 0x8000001a; + const uint STATUS_NO_SUCH_PRIVILEGE = 0xc0000060; + + internal sealed class Sid : IDisposable + { + public IntPtr pSid = IntPtr.Zero; + public SecurityIdentifier sid = null; + + public Sid(string sidString) + { + try + { + sid = new SecurityIdentifier(sidString); + } catch + { + throw new ArgumentException(String.Format("SID string {0} could not be converted to SecurityIdentifier", sidString)); + } + + Byte[] buffer = new Byte[sid.BinaryLength]; + sid.GetBinaryForm(buffer, 0); + + pSid = Marshal.AllocHGlobal(sid.BinaryLength); + Marshal.Copy(buffer, 0, pSid, sid.BinaryLength); + } + + public void Dispose() + { + if (pSid != IntPtr.Zero) + { + Marshal.FreeHGlobal(pSid); + pSid = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + ~Sid() { Dispose(); } + } + + [StructLayout(LayoutKind.Sequential)] + private struct LSA_OBJECT_ATTRIBUTES + { + public int Length; + public IntPtr RootDirectory; + public IntPtr ObjectName; + public int Attributes; + public IntPtr SecurityDescriptor; + public IntPtr SecurityQualityOfService; + } + + [StructLayout(LayoutKind.Sequential, CharSet = DEFAULT_CHAR_SET)] + private struct LSA_UNICODE_STRING + { + public ushort Length; + public ushort MaximumLength; + [MarshalAs(UnmanagedType.LPWStr)] + public string Buffer; + } + + [StructLayout(LayoutKind.Sequential)] + private struct LSA_ENUMERATION_INFORMATION + { + public IntPtr Sid; + } + + [DllImport(LSA_DLL, CharSet = DEFAULT_CHAR_SET, SetLastError = true)] + private static extern uint LsaOpenPolicy( + LSA_UNICODE_STRING[] SystemName, + ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, + int AccessMask, + out IntPtr PolicyHandle + ); + + [DllImport(LSA_DLL, CharSet = DEFAULT_CHAR_SET, SetLastError = true)] + private static extern uint LsaAddAccountRights( + IntPtr PolicyHandle, + IntPtr pSID, + LSA_UNICODE_STRING[] UserRights, + int CountOfRights + ); + + [DllImport(LSA_DLL, CharSet = DEFAULT_CHAR_SET, SetLastError = true)] + private static extern uint LsaRemoveAccountRights( + IntPtr PolicyHandle, + IntPtr pSID, + bool AllRights, + LSA_UNICODE_STRING[] UserRights, + int CountOfRights + ); + + [DllImport(LSA_DLL, CharSet = DEFAULT_CHAR_SET, SetLastError = true)] + private static extern uint LsaEnumerateAccountsWithUserRight( + IntPtr PolicyHandle, + LSA_UNICODE_STRING[] UserRights, + out IntPtr EnumerationBuffer, + out ulong CountReturned + ); + + [DllImport(LSA_DLL)] + private static extern int LsaNtStatusToWinError(int NTSTATUS); + + [DllImport(LSA_DLL)] + private static extern int LsaClose(IntPtr PolicyHandle); + + [DllImport(LSA_DLL)] + private static extern int LsaFreeMemory(IntPtr Buffer); + + public LsaRightHelper() + { + LSA_OBJECT_ATTRIBUTES lsaAttr; + lsaAttr.RootDirectory = IntPtr.Zero; + lsaAttr.ObjectName = IntPtr.Zero; + lsaAttr.Attributes = 0; + lsaAttr.SecurityDescriptor = IntPtr.Zero; + lsaAttr.SecurityQualityOfService = IntPtr.Zero; + lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES)); + + lsaHandle = IntPtr.Zero; + + LSA_UNICODE_STRING[] system = new LSA_UNICODE_STRING[1]; + system[0] = InitLsaString(""); + + uint ret = LsaOpenPolicy(system, ref lsaAttr, (int)Access.POLICY_ALL_ACCESS, out lsaHandle); + if (ret != 0) + throw new Win32Exception(LsaNtStatusToWinError((int)ret)); + } + + public void AddPrivilege(string sidString, string privilege) + { + uint ret = 0; + using (Sid sid = new Sid(sidString)) + { + LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1]; + privileges[0] = InitLsaString(privilege); + ret = LsaAddAccountRights(lsaHandle, sid.pSid, privileges, 1); + } + if (ret != 0) + throw new Win32Exception(LsaNtStatusToWinError((int)ret)); + } + + public void RemovePrivilege(string sidString, string privilege) + { + uint ret = 0; + using (Sid sid = new Sid(sidString)) + { + LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1]; + privileges[0] = InitLsaString(privilege); + ret = LsaRemoveAccountRights(lsaHandle, sid.pSid, false, privileges, 1); + } + if (ret != 0) + throw new Win32Exception(LsaNtStatusToWinError((int)ret)); + } + + public string[] EnumerateAccountsWithUserRight(string privilege) + { + uint ret = 0; + ulong count = 0; + LSA_UNICODE_STRING[] rights = new LSA_UNICODE_STRING[1]; + rights[0] = InitLsaString(privilege); + IntPtr buffer = IntPtr.Zero; + + ret = LsaEnumerateAccountsWithUserRight(lsaHandle, rights, out buffer, out count); + switch (ret) + { + case 0: + string[] accounts = new string[count]; + for (int i = 0; i < (int)count; i++) + { + LSA_ENUMERATION_INFORMATION LsaInfo = (LSA_ENUMERATION_INFORMATION)Marshal.PtrToStructure( + IntPtr.Add(buffer, i * Marshal.SizeOf(typeof(LSA_ENUMERATION_INFORMATION))), + typeof(LSA_ENUMERATION_INFORMATION)); + + accounts[i] = new SecurityIdentifier(LsaInfo.Sid).ToString(); + } + LsaFreeMemory(buffer); + return accounts; + + case STATUS_NO_MORE_ENTRIES: + return new string[0]; + + case STATUS_NO_SUCH_PRIVILEGE: + throw new ArgumentException(String.Format("Invalid privilege {0} not found in LSA database", privilege)); + + default: + throw new Win32Exception(LsaNtStatusToWinError((int)ret)); + } + } + + static LSA_UNICODE_STRING InitLsaString(string s) + { + // Unicode strings max. 32KB + if (s.Length > 0x7ffe) + throw new ArgumentException("String too long"); + + LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING(); + lus.Buffer = s; + lus.Length = (ushort)(s.Length * sizeof(char)); + lus.MaximumLength = (ushort)(lus.Length + sizeof(char)); + + return lus; + } + + public void Dispose() + { + if (lsaHandle != IntPtr.Zero) + { + LsaClose(lsaHandle); + lsaHandle = IntPtr.Zero; + } + GC.SuppressFinalize(this); + } + ~LsaRightHelper() { Dispose(); } + } +} +"@ + +Function Get-Username($sid) { + # converts the SID (if it is one) to a username + + $object = New-Object System.Security.Principal.SecurityIdentifier($sid) + $user = $object.Translate([System.Security.Principal.NTAccount]) + return $user.Value +} + +Function Get-SID($account_name) { + # Can take in the following account name forms and convert to a SID + # UPN: + # username@domain (Domain) + # Down-Level Login Name + # domain\username (Domain) + # computername\username (Local) + # .\username (Local) + # Login Name + # username (Local) + + if ($account_name -like "*\*") { + $account_name_split = $account_name -split "\\" + if ($account_name_split[0] -eq ".") { + $domain = $env:COMPUTERNAME + } else { + $domain = $account_name_split[0] + } + $username = $account_name_split[1] + } elseif ($account_name -like "*@*") { + $account_name_split = $account_name -split "@" + $domain = $account_name_split[1] + $username = $account_name_split[0] + } else { + $domain = $null + $username = $account_name + } + + if ($domain) { + # searching for a local group with the servername prefixed will fail, + # need to check for this situation and only use NTAccount(String) + if ($domain -eq $env:COMPUTERNAME) { + $adsi = [ADSI]("WinNT://$env:COMPUTERNAME,computer") + $group = $adsi.psbase.children | Where-Object { $_.schemaClassName -eq "group" } | Where-Object { $_.Name -eq $username } + } else { + $group = $null + } + if ($group) { + $account = New-Object System.Security.Principal.NTAccount($username) + } else { + $account = New-Object System.Security.Principal.NTAccount($domain, $username) + } + } else { + # when in a domain NTAccount(String) will favour domain lookups check + # if username is a local user and explictly search on the localhost for + # that account + $adsi = [ADSI]("WinNT://$env:COMPUTERNAME,computer") + $user = $adsi.psbase.children | Where-Object { $_.schemaClassName -eq "user" } | Where-Object { $_.Name -eq $username } + if ($user) { + $account = New-Object System.Security.Principal.NTAccount($env:COMPUTERNAME, $username) + } else { + $account = New-Object System.Security.Principal.NTAccount($username) + } + } + + try { + $account_sid = $account.Translate([System.Security.Principal.SecurityIdentifier]) + } catch { + Fail-Json $result "Account Name: $account_name is not a valid account, cannot get SID: $($_.Exception.Message)" + } + + return $account_sid.Value +} + +Function Compare-UserList($existing_users, $new_users) { + $added_users = [String[]]@() + $removed_users = [String[]]@() + if ($action -eq "add") { + $added_users = [Linq.Enumerable]::Except($new_users, $existing_users) + } elseif ($action -eq "remove") { + $removed_users = [Linq.Enumerable]::Intersect($new_users, $existing_users) + } else { + $added_users = [Linq.Enumerable]::Except($new_users, $existing_users) + $removed_users = [Linq.Enumerable]::Except($existing_users, $new_users) + } + + $change_result = @{ + added = $added_users + removed = $removed_users + } + + return $change_result +} + +# C# class we can use to enumerate/add/remove rights +$lsa_helper = New-Object -TypeName Ansible.LsaRightHelper + +$new_users = [System.Collections.ArrayList]@() +foreach ($user in $users) { + $new_users.Add((Get-SID -account_name $user)) +} +$new_users = [String[]]$new_users.ToArray() +try { + $existing_users = $lsa_helper.EnumerateAccountsWithUserRight($name) +} catch [ArgumentException] { + Fail-Json -obj $result -message "the specified right $name is not a valid right" +} catch { + Fail-Json -obj $result -message "failed to enumerate existing accounts with right: $($_.Exception.Message)" +} + +$change_result = Compare-UserList -existing_users $existing_users -new_user $new_users +if (($change_result.added.Length -gt 0) -or ($change_result.removed.Length -gt 0)) { + $result.changed = $true + $diff_text = "[$name]`n" + + # used in diff mode calculation + $new_user_list = [System.Collections.ArrayList]$existing_users + foreach ($user in $change_result.removed) { + if (-not $check_mode) { + $lsa_helper.RemovePrivilege($user, $name) + } + $user_name = Get-Username -sid $user + $result.removed += $user_name + $diff_text += "-$user_name`n" + $new_user_list.Remove($user) + } + foreach ($user in $change_result.added) { + if (-not $check_mode) { + $lsa_helper.AddPrivilege($user, $name) + } + $user_name = Get-Username -sid $user + $result.added += $user_name + $diff_text += "+$user_name`n" + $new_user_list.Add($user) + } + + if ($diff_mode) { + if ($new_user_list.Count -eq 0) { + $diff_text = "-$diff_text" + } else { + if ($existing_users.Count -eq 0) { + $diff_text = "+$diff_text" + } + } + $result.diff.prepared = $diff_text + } +} + +Exit-Json $result diff --git a/lib/ansible/modules/windows/win_user_right.py b/lib/ansible/modules/windows/win_user_right.py new file mode 100644 index 00000000000..022d341383d --- /dev/null +++ b/lib/ansible/modules/windows/win_user_right.py @@ -0,0 +1,97 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# This file is part of Ansible + +# Copyright (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +# this is a windows documentation stub. actual code lives in the .ps1 +# file of the same name + +ANSIBLE_METADATA = {'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = r''' +--- +module: win_user_right +version_added: '2.4' +short_description: Manage Windows User Rights +description: +- Add, remove or set User Rights for a group or users or groups. +- You can set user rights for both local and domain accounts. +notes: +- If the server is domain joined this module can change a right but if a GPO + governs this right then the changes won't last. +options: + name: + description: + - The name of the User Right as shown by the C(Constant Name) value from + U(https://technet.microsoft.com/en-us/library/dd349804.aspx). + - The module will return an error if the right is invalid. + required: True + users: + description: + - A list of users or groups to add/remove on the User Right. + - These can be in the form DOMAIN\user-group, user-group@DOMAIN.COM for + domain users/groups. + - For local users/groups it can be in the form user-group, .\user-group, + SERVERNAME\user-group where SERVERNAME is the name of the remote server. + - You can also add special local accounts like SYSTEM and others. + required: True + action: + description: + - C(add) will add the users/groups to the existing right. + - C(remove) will remove the users/groups from the existing right. + - C(set) will replace the users/groups of the existing right. + default: set + choices: [set, add, remove] +author: +- Jordan Borean (@jborean93) +''' + +EXAMPLES = r''' +--- +- name: replace the entries of Deny log on locally + win_user_right: + name: SeDenyInteractiveLogonRight + users: + - Guest + - Users + action: set + +- name: add account to Log on as a service + win_user_right: + name: SeServiceLogonRight + users: + - .\Administrator + - '{{ansible_hostname}}\local-user' + action: add + +- name: remove accounts who can create Symbolic links + win_user_right: + name: SeCreateSymbolicLinkPrivilege + users: + - SYSTEM + - Administrators + - DOMAIN\User + - group@DOMAIN.COM + action: remove +''' + +RETURN = r''' +added: + description: A list of accounts that were added to the right, this is empty + if no accounts were added. + returned: success + type: list + sample: ["NT AUTHORITY\\SYSTEM", "DOMAIN\\User"] +removed: + description: A list of accounts that were removed from the right, this is + empty if no accounts were removed. + returned: success + type: list + sample: ["SERVERNAME\\Administrator", "BUILTIN\\Administrators"] +''' diff --git a/test/integration/targets/win_user_right/aliases b/test/integration/targets/win_user_right/aliases new file mode 100644 index 00000000000..10e03fc2bf7 --- /dev/null +++ b/test/integration/targets/win_user_right/aliases @@ -0,0 +1 @@ +windows/ci/group1 diff --git a/test/integration/targets/win_user_right/defaults/main.yml b/test/integration/targets/win_user_right/defaults/main.yml new file mode 100644 index 00000000000..3db8c4f006b --- /dev/null +++ b/test/integration/targets/win_user_right/defaults/main.yml @@ -0,0 +1 @@ +test_win_user_right_name: SeRelabelPrivilege diff --git a/test/integration/targets/win_user_right/library/test_get_right.ps1 b/test/integration/targets/win_user_right/library/test_get_right.ps1 new file mode 100644 index 00000000000..e72887557d5 --- /dev/null +++ b/test/integration/targets/win_user_right/library/test_get_right.ps1 @@ -0,0 +1,44 @@ +#!powershell + +#Requires -Module Ansible.ModuleUtils.Legacy.psm1 + +# basic script to get the lsit of users in a particular right +# this is quite complex to put as a simple script so this is +# just a simple module + +$ErrorActionPreference = 'Stop' + +$params = Parse-Args $args -supports_check_mode $false +$name = Get-AnsibleParam -obj $params -name "name" -type "str" -failifempty $true + +$result = @{ + changed = $false + users = @() +} + +Function Get-Username($sid) { + $object = New-Object System.Security.Principal.SecurityIdentifier($sid) + $user = $object.Translate([System.Security.Principal.NTAccount]) + $user.Value +} + +$secedit_ini_path = [IO.Path]::GetTempFileName() +&SecEdit.exe /export /cfg $secedit_ini_path /quiet +$secedit_ini = Get-Content -Path $secedit_ini_path +Remove-Item -Path $secedit_ini_path -Force + +foreach ($line in $secedit_ini) { + if ($line.ToLower().StartsWith("$($name.ToLower()) = ")) { + $right_split = $line -split "=" + $existing_users = $right_split[-1].Trim() -split "," + foreach ($user in $existing_users) { + if ($user.StartsWith("*S")) { + $result.users += Get-Username -sid $user.substring(1) + } else { + $result.users += $user + } + } + } +} + +Exit-Json $result diff --git a/test/integration/targets/win_user_right/tasks/main.yml b/test/integration/targets/win_user_right/tasks/main.yml new file mode 100644 index 00000000000..8ab7ba3bb8f --- /dev/null +++ b/test/integration/targets/win_user_right/tasks/main.yml @@ -0,0 +1,25 @@ +--- +- name: get current entries for right + test_get_right: + name: '{{test_win_user_right_name}}' + register: actual_users + +- name: get facts + setup: + +- block: + - name: ensure right is empty before test + win_user_right: + name: '{{test_win_user_right_name}}' + users: [] + action: set + + - name: run tests + include_tasks: tests.yml + + always: + - name: reset entries for test right + win_user_right: + name: '{{test_win_user_right_name}}' + users: '{{actual_users.users}}' + action: set diff --git a/test/integration/targets/win_user_right/tasks/tests.yml b/test/integration/targets/win_user_right/tasks/tests.yml new file mode 100644 index 00000000000..e39c9d3c75c --- /dev/null +++ b/test/integration/targets/win_user_right/tasks/tests.yml @@ -0,0 +1,374 @@ +--- +- name: fail to set invalid right + win_user_right: + name: FailRight + users: Administrator + register: fail_invalid_right + failed_when: fail_invalid_right.msg != 'the specified right FailRight is not a valid right' + +- name: fail with invalid username + win_user_right: + name: '{{test_win_user_right_name}}' + users: FakeUser + register: fail_invalid_user + failed_when: "'Account Name: FakeUser is not a valid account, cannot get SID' not in fail_invalid_user.msg" + +- name: remove from empty right check + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Administrators'] + action: remove + register: remove_empty_right_check + check_mode: yes + +- name: assert remove from empty right check + assert: + that: + - not remove_empty_right_check|changed + - remove_empty_right_check.added == [] + - remove_empty_right_check.removed == [] + +- name: remove from empty right + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Administrators'] + action: remove + register: remove_empty_right + check_mode: yes + +- name: assert remove from empty right + assert: + that: + - not remove_empty_right|changed + - remove_empty_right.added == [] + - remove_empty_right.removed == [] + +- name: set administrator check + win_user_right: + name: '{{test_win_user_right_name}}' + users: Administrator + action: set + register: set_administrator_check + check_mode: yes + +- name: get actual set administrator check + test_get_right: + name: '{{test_win_user_right_name}}' + register: set_administrator_actual_check + +- name: assert set administrator check + assert: + that: + - set_administrator_check|changed + - set_administrator_check.added == ["{{ansible_hostname}}\\Administrator"] + - set_administrator_check.removed == [] + - set_administrator_actual_check.users == [] + +- name: set administrator + win_user_right: + name: '{{test_win_user_right_name}}' + users: Administrator + action: set + register: set_administrator + +- name: get actual set administrator + test_get_right: + name: '{{test_win_user_right_name}}' + register: set_administrator_actual + +- name: assert set administrator check + assert: + that: + - set_administrator|changed + - set_administrator.added == ["{{ansible_hostname}}\\Administrator"] + - set_administrator.removed == [] + - set_administrator_actual.users == ['Administrator'] + +- name: set administrator again + win_user_right: + name: '{{test_win_user_right_name}}' + users: Administrator + action: set + register: set_administrator_again + +- name: assert set administrator check + assert: + that: + - not set_administrator_again|changed + - set_administrator_again.added == [] + - set_administrator_again.removed == [] + +- name: remove from right check + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Guests', '{{ansible_hostname}}\Users', '.\Backup Operators'] + action: remove + register: remove_right_check + check_mode: yes + +- name: get actual remove from right check + test_get_right: + name: '{{test_win_user_right_name}}' + register: remove_right_actual_check + +- name: assert remove from right check + assert: + that: + - remove_right_check|changed + - remove_right_check.removed == ["{{ansible_hostname}}\\Administrator"] + - remove_right_check.added == [] + - remove_right_actual_check.users == ['Administrator'] + +- name: remove from right + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Guests', '{{ansible_hostname}}\Users', '.\Backup Operators'] + action: remove + register: remove_right + +- name: get actual remove from right + test_get_right: + name: '{{test_win_user_right_name}}' + register: remove_right_actual + +- name: assert remove from right + assert: + that: + - remove_right|changed + - remove_right.removed == ["{{ansible_hostname}}\\Administrator"] + - remove_right.added == [] + - remove_right_actual.users == [] + +- name: remove from right again + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Guests', '{{ansible_hostname}}\Users', '.\Backup Operators'] + action: remove + register: remove_right_again + +- name: assert remove from right + assert: + that: + - not remove_right_again|changed + - remove_right_again.removed == [] + - remove_right_again.added == [] + +- name: add to empty right check + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Administrators'] + action: add + register: add_right_on_empty_check + check_mode: yes + +- name: get actual add to empty right check + test_get_right: + name: '{{test_win_user_right_name}}' + register: add_right_on_empty_actual_check + +- name: assert add to empty right check + assert: + that: + - add_right_on_empty_check|changed + - add_right_on_empty_check.removed == [] + - add_right_on_empty_check.added == ["{{ansible_hostname}}\\Administrator", "BUILTIN\\Administrators"] + - add_right_on_empty_actual_check.users == [] + +- name: add to empty right + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Administrators'] + action: add + register: add_right_on_empty + +- name: get actual add to empty right + test_get_right: + name: '{{test_win_user_right_name}}' + register: add_right_on_empty_actual + +- name: assert add to empty right + assert: + that: + - add_right_on_empty|changed + - add_right_on_empty.removed == [] + - add_right_on_empty.added == ["{{ansible_hostname}}\\Administrator", "BUILTIN\\Administrators"] + - add_right_on_empty_actual.users == ["Administrator", "BUILTIN\\Administrators"] + +- name: add to empty right again + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Administrators'] + action: add + register: add_right_on_empty_again + +- name: assert add to empty right + assert: + that: + - not add_right_on_empty_again|changed + - add_right_on_empty_again.removed == [] + - add_right_on_empty_again.added == [] + +- name: add to existing right check + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Guests', '{{ansible_hostname}}\Users'] + action: add + register: add_right_on_existing_check + check_mode: yes + +- name: get actual add to existing right check + test_get_right: + name: '{{test_win_user_right_name}}' + register: add_right_on_existing_actual_check + +- name: assert add to existing right check + assert: + that: + - add_right_on_existing_check|changed + - add_right_on_existing_check.removed == [] + - add_right_on_existing_check.added == ["BUILTIN\\Guests", "BUILTIN\\Users"] + - add_right_on_existing_actual_check.users == ["Administrator", "BUILTIN\\Administrators"] + +- name: add to existing right + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Guests', '{{ansible_hostname}}\Users'] + action: add + register: add_right_on_existing + +- name: get actual add to existing right + test_get_right: + name: '{{test_win_user_right_name}}' + register: add_right_on_existing_actual + +- name: assert add to existing right + assert: + that: + - add_right_on_existing|changed + - add_right_on_existing.removed == [] + - add_right_on_existing.added == ["BUILTIN\\Guests", "BUILTIN\\Users"] + - add_right_on_existing_actual.users == ["Administrator", "BUILTIN\\Administrators", "BUILTIN\\Users", "BUILTIN\\Guests"] + +- name: add to existing right again + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrator', 'Guests', '{{ansible_hostname}}\Users'] + action: add + register: add_right_on_existing_again + +- name: assert add to existing right + assert: + that: + - not add_right_on_existing_again|changed + - add_right_on_existing_again.removed == [] + - add_right_on_existing_again.added == [] + +- name: remove from existing check + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Guests', 'Administrator'] + action: remove + register: remove_on_existing_check + check_mode: yes + +- name: get actual remove from existing check + test_get_right: + name: '{{test_win_user_right_name}}' + register: remove_on_existing_actual_check + +- name: assert remove from existing check + assert: + that: + - remove_on_existing_check|changed + - remove_on_existing_check.removed == ["BUILTIN\\Guests", "{{ansible_hostname}}\\Administrator"] + - remove_on_existing_check.added == [] + - remove_on_existing_actual_check.users == ["Administrator", "BUILTIN\\Administrators", "BUILTIN\\Users", "BUILTIN\\Guests"] + +- name: remove from existing + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Guests', 'Administrator'] + action: remove + register: remove_on_existing + +- name: get actual remove from existing + test_get_right: + name: '{{test_win_user_right_name}}' + register: remove_on_existing_actual + +- name: assert remove from existing + assert: + that: + - remove_on_existing|changed + - remove_on_existing.removed == ["BUILTIN\\Guests", "{{ansible_hostname}}\\Administrator"] + - remove_on_existing.added == [] + - remove_on_existing_actual.users == ["BUILTIN\\Administrators", "BUILTIN\\Users"] + +- name: remove from existing again + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Guests', 'Administrator'] + action: remove + register: remove_on_existing_again + +- name: assert remove from existing again + assert: + that: + - not remove_on_existing_again|changed + - remove_on_existing_again.removed == [] + - remove_on_existing_again.added == [] + +- name: set to existing check + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrators', 'SYSTEM', 'Backup Operators'] + action: set + register: set_on_existing_check + check_mode: yes + +- name: get actual set to existing check + test_get_right: + name: '{{test_win_user_right_name}}' + register: set_on_existing_actual_check + +- name: assert set to existing check + assert: + that: + - set_on_existing_check|changed + - set_on_existing_check.removed == ["BUILTIN\\Users"] + - set_on_existing_check.added == ["NT AUTHORITY\\SYSTEM", "BUILTIN\\Backup Operators"] + - set_on_existing_actual_check.users == ["BUILTIN\\Administrators", "BUILTIN\\Users"] + +- name: set to existing + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrators', 'SYSTEM', 'Backup Operators'] + action: set + register: set_on_existing + +- name: get actual set to existing + test_get_right: + name: '{{test_win_user_right_name}}' + register: set_on_existing_actual + +- name: assert set to existing + assert: + that: + - set_on_existing|changed + - set_on_existing.removed == ["BUILTIN\\Users"] + - set_on_existing.added == ["NT AUTHORITY\\SYSTEM", "BUILTIN\\Backup Operators"] + - set_on_existing_actual.users == ["NT AUTHORITY\\SYSTEM", "BUILTIN\\Administrators", "BUILTIN\\Backup Operators"] + +- name: set to existing again + win_user_right: + name: '{{test_win_user_right_name}}' + users: ['Administrators', 'SYSTEM', 'Backup Operators'] + action: set + register: set_on_existing_again + +- name: assert set to existing + assert: + that: + - not set_on_existing_again|changed + - set_on_existing_again.removed == [] + - set_on_existing_again.added == []