From 7a8bb0986b9b5054aaa72586ccd97257f1bac54c Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:10:22 -0500 Subject: [PATCH 01/49] Add Proxy option --- plugins/modules/win_psrepository.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/modules/win_psrepository.ps1 b/plugins/modules/win_psrepository.ps1 index 41923429..4db887a5 100644 --- a/plugins/modules/win_psrepository.ps1 +++ b/plugins/modules/win_psrepository.ps1 @@ -23,6 +23,7 @@ $script_publish_location = Get-AnsibleParam -obj $params -name "script_publish_l $state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present", "absent" $installation_policy = Get-AnsibleParam -obj $params -name "installation_policy" -type "str" -validateset "trusted", "untrusted" $force = Get-AnsibleParam -obj $params -name "force" -type "bool" -default $false +$proxy = Get-AnsibleParam -obj $params -name "proxy" -type "str" -failifempty $false $result = @{"changed" = $false} @@ -50,6 +51,10 @@ if ($installation_policy) { $repository_params.InstallationPolicy = $installation_policy } +if ($proxy) { + $repository_params.Proxy = $Proxy +} + function Resolve-LocationParameter { [CmdletBinding()] param( From 9a9edc524777ee376c87c2d0818264b37ee9e304 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 20 Aug 2020 16:10:59 -0500 Subject: [PATCH 02/49] add proxy to doc --- plugins/modules/win_psrepository.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/modules/win_psrepository.py b/plugins/modules/win_psrepository.py index b1ca443b..b0076ace 100644 --- a/plugins/modules/win_psrepository.py +++ b/plugins/modules/win_psrepository.py @@ -57,6 +57,11 @@ - I(force) has no effect when I(state=absent). See notes for additional context. type: bool default: False + proxy: + description: + - Proxy to use for repository. + type: str + required: no requirements: - PowerShell Module L(PowerShellGet >= 1.6.0,https://www.powershellgallery.com/packages/PowerShellGet/) - PowerShell Module L(PackageManagement >= 1.1.7,https://www.powershellgallery.com/packages/PackageManagement/) From 6dec2b7818cbd434150ad8085c2587cdefd0bc3b Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 7 Sep 2020 20:27:24 -0500 Subject: [PATCH 03/49] version_added: 1.1.0 --- plugins/modules/win_psrepository.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/win_psrepository.py b/plugins/modules/win_psrepository.py index b0076ace..38643d0b 100644 --- a/plugins/modules/win_psrepository.py +++ b/plugins/modules/win_psrepository.py @@ -62,6 +62,7 @@ - Proxy to use for repository. type: str required: no + version_added: 1.1.0 requirements: - PowerShell Module L(PowerShellGet >= 1.6.0,https://www.powershellgallery.com/packages/PowerShellGet/) - PowerShell Module L(PackageManagement >= 1.1.7,https://www.powershellgallery.com/packages/PackageManagement/) From ca74f4429033f94efcdb3429133635f976e23626 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Wed, 3 Mar 2021 12:38:11 -0600 Subject: [PATCH 04/49] Adding win_feature_info module --- plugins/modules/win_feature_info.ps1 | 49 +++++ plugins/modules/win_feature_info.py | 276 +++++++++++++++++++++++++++ 2 files changed, 325 insertions(+) create mode 100644 plugins/modules/win_feature_info.ps1 create mode 100644 plugins/modules/win_feature_info.py diff --git a/plugins/modules/win_feature_info.ps1 b/plugins/modules/win_feature_info.ps1 new file mode 100644 index 00000000..a9fbcdd9 --- /dev/null +++ b/plugins/modules/win_feature_info.ps1 @@ -0,0 +1,49 @@ +#!powershell + +# Copyright: (c) 2020, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.Basic +#AnsibleRequires -CSharpUtil ansible_collections.ansible.windows.plugins.module_utils.SCManager + +$spec = @{ + options = @{ + name = @{ type = "str"; default = '*' } + } + supports_check_mode = $true +} + +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +$name = $module.Params.name + +$module.Result.exists = $false + +$features = Get-WindowsFeature -Name $name + +$module.Result.features = @(foreach ($feature in ($features)) { + # These should closely reflect the options for win_feature + [Ordered]@{ + name = $feature.Name + display_name = $feature.DisplayName + description = $feature.Description + installed = $feature.Installed + install_state = $feature.InstallState.ToString() + feature_type = $feature.FeatureType + path = $feature.Path + depth = $feature.Depth + depends_on = $feature.DependsOn + parent = $feature.Parent + server_component_descriptor = $feature.ServerComponentDescriptor + sub_features = $feature.SubFeatures + system_service = $feature.SystemService + notification = $feature.Notification + best_practices_model_id = $feature.BestPracticesModelId + event_query = $feature.EventQuery + post_configuration_needed = $feature.PostConfigurationNeeded + additional_info = $feature.AdditionalInfo + } + $module.Result.exists = $true + }) + +$module.ExitJson() diff --git a/plugins/modules/win_feature_info.py b/plugins/modules/win_feature_info.py new file mode 100644 index 00000000..a23716db --- /dev/null +++ b/plugins/modules/win_feature_info.py @@ -0,0 +1,276 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020, Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION = r''' +--- +module: win_feature_info +short_description: Gather information about Windows features +description: +- Gather information about all or a specific installed Windows feature(s). +options: + name: + description: + - If specified, this is used to match the C(name) of the Windows feature to get the info for. + - Can be a wildcard to match multiple features but the wildcard will only be matched on the C(name) of the feature. + - If omitted then all features will returned. + type: str + default: '*' +seealso: +- module: ansible.windows.win_feature +author: +- Larry Lane (@gamethis) +''' + +EXAMPLES = r''' +- name: Get info for all installed features + community.windows.win_feature_info: + register: feature_info +- name: Get info for a single feature + community.windows.win_feature_info: + name: DNS + register: feature_info +- name: Find all features that start with 'FS' + ansible.windows.win_feature_info: + name: FS* +''' + +RETURN = r''' +exists: + description: Whether any features were found based on the criteria specified. + returned: always + type: bool + sample: true +features: + description: + - A list of feature(s) that were found based on the criteria. + - Will be an empty list if no features were found. + returned: always + type: list + elements: dict + contains: + name: + description: + - Name of feature found. + type: str + sample: AD-Certificate + display_name: + description: + - The Display name of feature found. + type: str + sample: Active Directory Certificate Services + description: + description: + - The description of the feature. + type: str + sample: Example description of the Windows feature. + installed: + description: + - Whether the feature by C(name) is installed. + type: bool + sample: false + install_state: + description: + - The Install State of C(name). + - Values will be one of C(Available), C(Removed), C(Installed). + type: str + sample: Installed + feature_type: + description: + - The Feature Type of C(name). + - Values will be one of C(Role), C(Role Service), C(Feature). + type: str + sample: Feature + path: + description: + - The Path of C(name) feature. + type: str + sample: WoW64 Support + depth: + description: + - Depth of C(name) feature. + type: int + sample: 1 + depends_on: + description: + - The command line that will be run when a C(run_command) failure action is fired. + type: list + elements: str + sample: ['Web-Static-Content', 'Web-Default-Doc'] + parent: + description: + - The parent of feature C(name) if present. + type: str + sample: PowerShellRoot + server_component_descriptor: + description: + - Descriptor of C(name) feature. + type: str + sample: ServerComponent_AD_Certificate + sub_features: + description: + - List of sub features names of feature C(name). + type: list + elements: str + sample: ['WAS-Process-Model', 'WAS-NET-Environment', 'WAS-Config-APIs'] + system_service: + description: + - The name of the service installed by feature C(name). + type: list + elements: str + sample: ['iisadmin', 'w3svc'] + notification: + description: + - Notifications from feature. + - The binary part can be quoted to ensure any spaces in path are not treated as arguments. + type: list + element: str + sample: [] + best_practices_model_id: + description: + - BestPracticesModelId for feature C(name). + type: str + sample: Microsoft/Windows/UpdateServices + event_query: + description: + - The EventQuery for feature C(name). + - This will be C(null) if None Present + type: str + sample: IPAMServer.Events.xml + post_configuration_needed: + description: + - Tells if Post Configuration is needed for feature C(name). + type: bool + sample: False + additional_info: + description: + - A list of privileges that the feature requires and will run with + type: dict + contains: + major_version: + description: + - Major Version of feature C(name). + type: int + sample: 8 + minor_version: + description: + - Minor Version of feature C(name). + type: int + sample: 0 + number_id_version: + description: + - Numberic Id of feature C(name). + type: int + sample: 16 + install_name: + description: + - The action to perform once triggered, can be C(start_feature) or C(stop_feature). + type: str + sample: ADCertificateServicesRole + contains: str + sample: ['SeBackupPrivilege', 'SeRestorePrivilege'] + feature_exit_code: + description: + - A feature-specific error code that is set while the feature is starting or stopping. + type: int + sample: 0 + feature_flags: + description: + - Shows more information about the behaviour of a running feature. + - Currently the only flag that can be set is C(runs_in_system_process). + type: list + elements: str + sample: [ 'runs_in_system_process' ] + feature_type: + description: + - The type of feature. + - Common types are C(win32_own_process), C(win32_share_process), C(user_own_process), C(user_share_process), + C(kernel_driver). + type: str + sample: win32_own_process + sid_info: + description: + - The behavior of how the feature's access token is generated and how to add the feature SID to the token. + - Common values are C(none), C(restricted), or C(unrestricted). + type: str + sample: none + start_mode: + description: + - When the feature is set to start. + - Common values are C(auto), C(manual), C(disabled), C(delayed). + type: str + sample: auto + state: + description: + - The current running state of the feature. + - Common values are C(stopped), C(start_pending), C(stop_pending), C(started), C(continue_pending), + C(pause_pending), C(paused). + type: str + sample: started + triggers: + description: + - A list of triggers defined for the feature. + type: list + elements: dict + contains: + action: + description: + - The action to perform once triggered, can be C(start_feature) or C(stop_feature). + type: str + sample: start_feature + data_items: + description: + - A list of trigger data items that contain trigger specific data. + - A trigger can contain 0 or multiple data items. + type: list + elements: dict + contains: + data: + description: + - The trigger data item value. + - Can be a string, list of string, int, or base64 string of binary data. + type: complex + sample: named pipe + type: + description: + - The type of C(data) for the trigger. + - Common values are C(string), C(binary), C(level), C(keyword_any), or C(keyword_all). + type: str + sample: string + sub_type: + description: + - The trigger event sub type that is specific to each C(type). + - Common values are C(named_pipe_event), C(domain_join), C(domain_leave), C(firewall_port_open), and others. + type: str + sample: + sub_type_guid: + description: + - The guid which represents the trigger sub type. + type: str + sample: 1ce20aba-9851-4421-9430-1ddeb766e809 + type: + description: + - The trigger event type. + - Common values are C(custom), C(rpc_interface_event), C(domain_join), C(group_policy), and others. + type: str + sample: domain_join + username: + description: + - The username used to run the feature. + - Can be null for user features and certain driver features. + type: str + sample: NT AUTHORITY\SYSTEM + wait_hint_ms: + description: + - The estimated time in milliseconds required for a pending start, stop, pause,or continue operations. + type: int + sample: 0 + win32_exitcode: + description: + - The error code returned from the feature binary once it has stopped. + - When set to C(1066) then a feature specific error is returned on C(feature_exit_code). + type: int + sample: 0 +''' From fc2638afe16c87e0dd1d3afbd7afa6f85eec529d Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Wed, 3 Mar 2021 12:51:59 -0600 Subject: [PATCH 05/49] fixing win_feature_info doc file --- plugins/modules/win_feature_info.py | 104 ---------------------------- 1 file changed, 104 deletions(-) diff --git a/plugins/modules/win_feature_info.py b/plugins/modules/win_feature_info.py index a23716db..45659c65 100644 --- a/plugins/modules/win_feature_info.py +++ b/plugins/modules/win_feature_info.py @@ -169,108 +169,4 @@ - The action to perform once triggered, can be C(start_feature) or C(stop_feature). type: str sample: ADCertificateServicesRole - contains: str - sample: ['SeBackupPrivilege', 'SeRestorePrivilege'] - feature_exit_code: - description: - - A feature-specific error code that is set while the feature is starting or stopping. - type: int - sample: 0 - feature_flags: - description: - - Shows more information about the behaviour of a running feature. - - Currently the only flag that can be set is C(runs_in_system_process). - type: list - elements: str - sample: [ 'runs_in_system_process' ] - feature_type: - description: - - The type of feature. - - Common types are C(win32_own_process), C(win32_share_process), C(user_own_process), C(user_share_process), - C(kernel_driver). - type: str - sample: win32_own_process - sid_info: - description: - - The behavior of how the feature's access token is generated and how to add the feature SID to the token. - - Common values are C(none), C(restricted), or C(unrestricted). - type: str - sample: none - start_mode: - description: - - When the feature is set to start. - - Common values are C(auto), C(manual), C(disabled), C(delayed). - type: str - sample: auto - state: - description: - - The current running state of the feature. - - Common values are C(stopped), C(start_pending), C(stop_pending), C(started), C(continue_pending), - C(pause_pending), C(paused). - type: str - sample: started - triggers: - description: - - A list of triggers defined for the feature. - type: list - elements: dict - contains: - action: - description: - - The action to perform once triggered, can be C(start_feature) or C(stop_feature). - type: str - sample: start_feature - data_items: - description: - - A list of trigger data items that contain trigger specific data. - - A trigger can contain 0 or multiple data items. - type: list - elements: dict - contains: - data: - description: - - The trigger data item value. - - Can be a string, list of string, int, or base64 string of binary data. - type: complex - sample: named pipe - type: - description: - - The type of C(data) for the trigger. - - Common values are C(string), C(binary), C(level), C(keyword_any), or C(keyword_all). - type: str - sample: string - sub_type: - description: - - The trigger event sub type that is specific to each C(type). - - Common values are C(named_pipe_event), C(domain_join), C(domain_leave), C(firewall_port_open), and others. - type: str - sample: - sub_type_guid: - description: - - The guid which represents the trigger sub type. - type: str - sample: 1ce20aba-9851-4421-9430-1ddeb766e809 - type: - description: - - The trigger event type. - - Common values are C(custom), C(rpc_interface_event), C(domain_join), C(group_policy), and others. - type: str - sample: domain_join - username: - description: - - The username used to run the feature. - - Can be null for user features and certain driver features. - type: str - sample: NT AUTHORITY\SYSTEM - wait_hint_ms: - description: - - The estimated time in milliseconds required for a pending start, stop, pause,or continue operations. - type: int - sample: 0 - win32_exitcode: - description: - - The error code returned from the feature binary once it has stopped. - - When set to C(1066) then a feature specific error is returned on C(feature_exit_code). - type: int - sample: 0 ''' From d20bfe3df790cc23d0dff71cdcaa088817faa56c Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Wed, 3 Mar 2021 13:11:31 -0600 Subject: [PATCH 06/49] Update win_feature_info.py --- plugins/modules/win_feature_info.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plugins/modules/win_feature_info.py b/plugins/modules/win_feature_info.py index 45659c65..2eba596d 100644 --- a/plugins/modules/win_feature_info.py +++ b/plugins/modules/win_feature_info.py @@ -121,13 +121,6 @@ type: list elements: str sample: ['iisadmin', 'w3svc'] - notification: - description: - - Notifications from feature. - - The binary part can be quoted to ensure any spaces in path are not treated as arguments. - type: list - element: str - sample: [] best_practices_model_id: description: - BestPracticesModelId for feature C(name). From c465d779c933550cb26ca5c5b469619c4001f590 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Wed, 3 Mar 2021 13:12:12 -0600 Subject: [PATCH 07/49] Update win_feature_info.ps1 --- plugins/modules/win_feature_info.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/modules/win_feature_info.ps1 b/plugins/modules/win_feature_info.ps1 index a9fbcdd9..ace25756 100644 --- a/plugins/modules/win_feature_info.ps1 +++ b/plugins/modules/win_feature_info.ps1 @@ -37,7 +37,6 @@ $module.Result.features = @(foreach ($feature in ($features)) { server_component_descriptor = $feature.ServerComponentDescriptor sub_features = $feature.SubFeatures system_service = $feature.SystemService - notification = $feature.Notification best_practices_model_id = $feature.BestPracticesModelId event_query = $feature.EventQuery post_configuration_needed = $feature.PostConfigurationNeeded From a0ad39c2ba0039005e1d097386a1879423678b83 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 12 Mar 2021 07:53:10 -0600 Subject: [PATCH 08/49] added version_added: '1.4.0' --- plugins/modules/win_feature_info.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/win_feature_info.py b/plugins/modules/win_feature_info.py index 2eba596d..c35d8c36 100644 --- a/plugins/modules/win_feature_info.py +++ b/plugins/modules/win_feature_info.py @@ -7,6 +7,7 @@ DOCUMENTATION = r''' --- module: win_feature_info +version_added: '1.4.0' short_description: Gather information about Windows features description: - Gather information about all or a specific installed Windows feature(s). From d6b684986b36ba52023cfa5bff5269137f9d0757 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 12 Mar 2021 07:55:01 -0600 Subject: [PATCH 09/49] removed ordered, and unneeded lines at top --- plugins/modules/win_feature_info.ps1 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plugins/modules/win_feature_info.ps1 b/plugins/modules/win_feature_info.ps1 index ace25756..13fd69d8 100644 --- a/plugins/modules/win_feature_info.ps1 +++ b/plugins/modules/win_feature_info.ps1 @@ -1,11 +1,5 @@ #!powershell -# Copyright: (c) 2020, Ansible Project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -#AnsibleRequires -CSharpUtil Ansible.Basic -#AnsibleRequires -CSharpUtil ansible_collections.ansible.windows.plugins.module_utils.SCManager - $spec = @{ options = @{ name = @{ type = "str"; default = '*' } @@ -23,7 +17,7 @@ $features = Get-WindowsFeature -Name $name $module.Result.features = @(foreach ($feature in ($features)) { # These should closely reflect the options for win_feature - [Ordered]@{ + @{ name = $feature.Name display_name = $feature.DisplayName description = $feature.Description From 40e1f3c85a41730b40405db930be4ea32402382c Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 12 Mar 2021 08:32:55 -0600 Subject: [PATCH 10/49] Ading tests --- .../targets/win_feature_info/aliases | 1 + .../win_feature_info/defaults/main.yml | 11 ++++ .../targets/win_feature_info/tasks/main.yml | 58 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 tests/integration/targets/win_feature_info/aliases create mode 100644 tests/integration/targets/win_feature_info/defaults/main.yml create mode 100644 tests/integration/targets/win_feature_info/tasks/main.yml diff --git a/tests/integration/targets/win_feature_info/aliases b/tests/integration/targets/win_feature_info/aliases new file mode 100644 index 00000000..4cd27b3c --- /dev/null +++ b/tests/integration/targets/win_feature_info/aliases @@ -0,0 +1 @@ +shippable/windows/group1 diff --git a/tests/integration/targets/win_feature_info/defaults/main.yml b/tests/integration/targets/win_feature_info/defaults/main.yml new file mode 100644 index 00000000..86fc61ae --- /dev/null +++ b/tests/integration/targets/win_feature_info/defaults/main.yml @@ -0,0 +1,11 @@ +--- +test_path: '{{ remote_tmp_dir }}\win_service_info .ÅÑŚÌβŁÈ [$!@^&test(;)]' +service_url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_service/SleepService.exe + +service_name1: ansible_service_info_test [*abc] +service_name2: ansible_service_info_test2 +service_name3: ansible_service_info_other +service_names: +- '{{ service_name1 }}' +- '{{ service_name2 }}' +- '{{ service_name3 }}' diff --git a/tests/integration/targets/win_feature_info/tasks/main.yml b/tests/integration/targets/win_feature_info/tasks/main.yml new file mode 100644 index 00000000..4d992263 --- /dev/null +++ b/tests/integration/targets/win_feature_info/tasks/main.yml @@ -0,0 +1,58 @@ +--- +- name: test we can get info for all features + win_feature_info: + register: all_actual + check_mode: yes # tests that this will run in check mode + +- name: assert test we can get info for all features + assert: + that: + - all_actual.exists + - not all_actual is changed + +- name: test info on a missing feature + win_feature_info: + name: ansible_feature_info_missing + register: missing_feature + +- name: assert test info on a missing feature + assert: + that: + - not missing_feature is changed + - not missing_feature.exists + +- name: Install Test Feature + ansible.windows.win_feature: + name: "{{ test_feature }}" + state: present + +- name: test info on a single Feature + win_feature_info: + name: '{{ test_feature }}' + register: specific_feature + +- name: assert test info on single feature + assert: + that: + - not specific_feature is changed + - specific_feature.exists + - specific_feature.features | length == 1 + - specific_feature.features[0].install_state == "Installed" + +- name: Uninstall Test Feature + ansible.windows.win_feature: + name: "{{ test_feature }}" + state: absent + +- name: test info on a single Feature + win_feature_info: + name: '{{ test_feature }}' + register: specific_feature + +- name: assert test info on single feature + assert: + that: + - not specific_feature is changed + - specific_feature.exists + - specific_feature.features | length == 1 + - specific_feature.features[0].install_state == "Available" From 49863aa766ec511176f9622046ab9ad8d752abaa Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 12 Mar 2021 08:38:03 -0600 Subject: [PATCH 11/49] added gnu back --- plugins/modules/win_feature_info.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/modules/win_feature_info.ps1 b/plugins/modules/win_feature_info.ps1 index 13fd69d8..a2be14de 100644 --- a/plugins/modules/win_feature_info.ps1 +++ b/plugins/modules/win_feature_info.ps1 @@ -1,5 +1,7 @@ #!powershell +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + $spec = @{ options = @{ name = @{ type = "str"; default = '*' } From 219ef6d70f093d9ff5c93114adfffda3a5ed4e20 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 12 Mar 2021 08:47:59 -0600 Subject: [PATCH 12/49] put proper basic import in --- plugins/modules/win_feature_info.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/win_feature_info.ps1 b/plugins/modules/win_feature_info.ps1 index a2be14de..78e4f574 100644 --- a/plugins/modules/win_feature_info.ps1 +++ b/plugins/modules/win_feature_info.ps1 @@ -1,6 +1,7 @@ #!powershell # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +#AnsibleRequires -CSharpUtil Ansible.Basic $spec = @{ options = @{ From 4f62b9e95cac1f6746b8af4816f90bfc669ee4f1 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Sat, 13 Mar 2021 11:20:06 -0600 Subject: [PATCH 13/49] trying different alias --- tests/integration/targets/win_feature_info/aliases | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/win_feature_info/aliases b/tests/integration/targets/win_feature_info/aliases index 4cd27b3c..215e0b06 100644 --- a/tests/integration/targets/win_feature_info/aliases +++ b/tests/integration/targets/win_feature_info/aliases @@ -1 +1 @@ -shippable/windows/group1 +shippable/windows/group4 From 10d1bcf9ec0a21268093088257e6667e4d5cd330 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Sat, 13 Mar 2021 11:29:44 -0600 Subject: [PATCH 14/49] updated with test_feature --- .../targets/win_feature_info/defaults/main.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/integration/targets/win_feature_info/defaults/main.yml b/tests/integration/targets/win_feature_info/defaults/main.yml index 86fc61ae..668a5343 100644 --- a/tests/integration/targets/win_feature_info/defaults/main.yml +++ b/tests/integration/targets/win_feature_info/defaults/main.yml @@ -1,11 +1,2 @@ --- -test_path: '{{ remote_tmp_dir }}\win_service_info .ÅÑŚÌβŁÈ [$!@^&test(;)]' -service_url: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/win_service/SleepService.exe - -service_name1: ansible_service_info_test [*abc] -service_name2: ansible_service_info_test2 -service_name3: ansible_service_info_other -service_names: -- '{{ service_name1 }}' -- '{{ service_name2 }}' -- '{{ service_name3 }}' +test_feature: "Web-Server" From 399a65775c8a53cd0512beaa56cd7a0eee8e2d56 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Sat, 13 Mar 2021 12:03:14 -0600 Subject: [PATCH 15/49] updated names for clarity of test --- .../targets/win_feature_info/tasks/main.yml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/integration/targets/win_feature_info/tasks/main.yml b/tests/integration/targets/win_feature_info/tasks/main.yml index 4d992263..a6fdb28f 100644 --- a/tests/integration/targets/win_feature_info/tasks/main.yml +++ b/tests/integration/targets/win_feature_info/tasks/main.yml @@ -29,15 +29,15 @@ - name: test info on a single Feature win_feature_info: name: '{{ test_feature }}' - register: specific_feature + register: specific_feature_present - name: assert test info on single feature assert: that: - - not specific_feature is changed - - specific_feature.exists - - specific_feature.features | length == 1 - - specific_feature.features[0].install_state == "Installed" + - not specific_feature_present is changed + - specific_feature_present.exists + - specific_feature_present.features | length == 1 + - specific_feature_present.features[0].install_state == "Installed" - name: Uninstall Test Feature ansible.windows.win_feature: @@ -47,12 +47,12 @@ - name: test info on a single Feature win_feature_info: name: '{{ test_feature }}' - register: specific_feature + register: specific_feature_absent - name: assert test info on single feature assert: that: - - not specific_feature is changed - - specific_feature.exists - - specific_feature.features | length == 1 - - specific_feature.features[0].install_state == "Available" + - not specific_feature_absent is changed + - specific_feature_absent.exists + - specific_feature_absent.features | length == 1 + - specific_feature_absent.features[0].install_state == "Available" From 47adcb9cf427c350fc9c9e9e202846b647ff29c8 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:46:09 -0500 Subject: [PATCH 16/49] added win_domain_ou module --- plugins/modules/win_domain_ou.ps1 | 302 ++++++++++++++++++++++++++++++ plugins/modules/win_domain_ou.py | 146 +++++++++++++++ 2 files changed, 448 insertions(+) create mode 100644 plugins/modules/win_domain_ou.ps1 create mode 100644 plugins/modules/win_domain_ou.py diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 new file mode 100644 index 00000000..b74d559e --- /dev/null +++ b/plugins/modules/win_domain_ou.ps1 @@ -0,0 +1,302 @@ +#!powershell + +# Copyright: (c) 2020 VMware, Inc. All Rights Reserved. +# SPDX-License-Identifier: GPL-3.0-only +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +#AnsibleRequires -CSharpUtil Ansible.Basic +#Requires -Module Ansible.ModuleUtils.CamelConversion +#Requires -Module ActiveDirectory + +$spec = @{ + options = @{ + state = @{ type = "str"; choices = @("absent", "present"); default = "present" } + name = @{ type = "str"; required = $true } + protected = @{ type = "bool"; default = $false } + path = @{ type = "str"; required = $false } + filter = @{type = "str"; default = '*';} + recursive = @{ type = "bool"; default = $false } + domain_username = @{ type = "str"; } + domain_password = @{ type = "str"; no_log = $true } + domain_server = @{ type = "str"; } + properties = @{ type = "dict";} + } + required_together = @( + ,@('domain_password', 'domain_username') + ) + supports_check_mode = $true +} + +$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec) + +$extra_args = @{} +$onboard_extra_args = @{} +if ($null -ne $module.Params.domain_username) { + $domain_password = ConvertTo-SecureString $module.Params.domain_password -AsPlainText -Force + $credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $module.Params.domain_username, $domain_password + $extra_args.Credential = $credential + $onboard_extra_args.Credential = $credential +} +if ($null -ne $module.Params.domain_server) { + $extra_args.Server = $module.Params.domain_server + $onboard_extra_args.Server = $module.Params.domain_server +} +if ($module.Params.properties.count -ne 0){ + $extra_args.Properties = "" + $module.Params.properties.Keys | Foreach-Object{ + $extra_args.Properties = New-Object Collections.Generic.List[string] + $item = $_ + $keyName = "" + if ($item.Contains("_")){ + $item.Split("_") | Foreach-Object{ + write-host $_ + $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() + } + }else{ + $keyName = $item.substring(0,1).toupper() + $item.substring(1).tolower() + } + $extra_args.Properties.Add($keyName) + } +}else{ + $extra_args.Properties = '*' +} + +$extra_args.Filter = $module.Params.filter +$check_mode = $module.CheckMode + +$name = $module.Params.name +$protected = $module.Params.protected +$path = $module.Params.path +$state = $module.Params.state +$recursive = $module.Params.recursive + +# setup Dynamic Params +$parms = @{} +if ($module.Params.properties.count -ne 0){ + $module.Params.properties.Keys | ForEach-Object{ + $item = $_ + $keyName = "" + if ($item.Contains("_")){ + $item.Split("_") | Foreach-Object{ + write-host $_ + $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() + } + }else{ + $keyName = $item.substring(0,1).toupper() + $item.substring(1).tolower() + } + $parms.Add($keyName,$module.Params.properties.Item($_)) + } +} +$module.Result.params = $parms + +Function Compare-OuObject { + Param( + [PSObject]$Original, + [PSObject]$Updated, + [string]$properties + ) + if ($Original -eq $false) { return $false } + if ($properties -ne '*'){ + $x = Compare-Object -ReferenceObject $Original -DifferenceObject $Updated -Property $properties + }else{ + $x = Compare-Object -ReferenceObject $Original -DifferenceObject $Updated + } + $x.Count -eq 0 +} + +Function Get-SimulatedOu { + Param($Object) + + $parms = @{ + Name = $Object.name + DistinguishedName = "OU=$($Object.name)," + $Object.path + ProtectedFromAccidentalDeletion = $Object.protected + } + + if ($Object.properties) { + if ($Object.properties.description) { $parms.Description = $Object.properties.description } + if ($Object.properties.city) { $parms.City = $Object.properties.city } + if ($Object.properties.state) { $parms.State = $Object.properties.state } + if ($Object.properties.street_address) { $parms.StreetAddress = $Object.properties.street_address } + if ($Object.properties.postal_code) { $parms.PostalCode = $Object.properties.postal_code } + if ($Object.properties.country) { $parms.Country = $Object.properties.country } + if ($Object.properties.managed_by) { $parms.ManagedBy = $Object.properties.managed_by } + } + + # convert to psobject & return + [PSCustomObject]$parms +} +function Convert-ObjectToSnakeCase { + <# + .SYNOPSIS + Converts an object with CamelCase properties to a dictionary with snake_case keys. + Works in the spirit of and depends on the existing CamelConversion module util. + #> + [CmdletBinding()] + param( + [Parameter(Mandatory=$true,ValueFromPipeline=$true)] + [OutputType([System.Collections.Specialized.OrderedDictionary])] + [Object] + $InputObject , + + [Parameter()] + [Switch] + $NoRecurse , + + [Parameter()] + [Switch] + $OmitNull + ) + + Process { + $result = [Ordered]@{} + foreach ($property in $InputObject.PSObject.Properties) { + $value = $property.Value + if (-not $NoRecurse -and $value -is [System.Collections.IDictionary]) { + $value = Convert-DictToSnakeCase -dict $value + } + elseif (-not $NoRecurse -and ($value -is [Array] -or $value -is [System.Collections.ArrayList])) { + $value = Convert-ListToSnakeCase -list $value + } + elseif ($null -eq $value) { + if ($OmitNull) { + continue + } + } + elseif (-not $NoRecurse -and $value -isnot [System.ValueType] -and $value -isnot [string]) { + $value = Convert-ObjectToSnakeCase -InputObject $value + } + + $name = Convert-StringToSnakeCase -string $property.Name + $result[$name] = $value + } + $result + } +} +Function Get-OuObject { + Param([PSObject]$Object) + $obj = $Object | Select-Object -Property * -ExcludeProperty ObjectGUID,nTSecurityDescriptor + $obj = Convert-ObjectToSnakeCase -InputObject $obj -NoRecurse + try{$obj.object_guid = $Object.ObjectGUID} + catch{$module.FailJson("Adding objectGUid $($_.Exception.Message)", $_)} + return $obj +} + +# attempt import of module +Try { Import-Module ActiveDirectory } +Catch { $module.FailJson("The ActiveDirectory module failed to load properly: $($_.Exception.Message)", $_) } + +Try{ + $module.Result.extra_args = $extra_args + $all_ous = Get-ADOrganizationalUnit @extra_args +}Catch{$module.FailJson("Line 191: Get-ADOrganizationalUnit failed: $($_.Exception.Message)", $_) } + + +# set path if not defined to base domain +if ($null -eq $path){ + if ($($all_ous | Measure-Object | Select-Object -ExpandProperty Count) -eq 1){ + $matched = $all_ous.DistinguishedName -match "DC=.+" + + }elseif ($($all_ous | Measure-Object | Select-Object -ExpandProperty Count) -gt 1) { + $matched = $all_ous[0].DistinguishedName -match "DC=.+" + }else{ + $module.FailJson("path was null and unable to determine default domain $($_.Exception.Message)", $_) + } + $path = $matches.Values[0] +} + +# determine if requested OU exist +Try { + $current_ou = $all_ous | Where-Object { + $_.DistinguishedName -eq "OU=$name,$path"} + $module.Diff.before = Get-OuObject -Object $current_ou + $module.Result.ou = $module.Diff.before +} Catch { + #$module.FailJson("current_ou error $($_.Exception.Message)", $_) + $module.Diff.before = "" + $current_ou = $false +} + +if ($state -eq "present") { + # ou does not exist, create object + if(-not $current_ou) { + $parms.Name = $name + $parms.Path = $path + Try { + $module.Result.params = $parms + $module.Result.extra_args = $onboard_extra_args + New-ADOrganizationalUnit @parms @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode + }Catch { + $module.FailJson("Failed to create organizational unit: $($_.Exception.Message)", $_) + } + } + + # ou exists, update object + if ($current_ou) { + Try { + $module.Result.params = $parms + $module.Result.extra_args = $onboard_extra_args + Set-ADOrganizationalUnit -Identity "OU=$name,$path" @parms @onboard_extra_args -WhatIf:$check_mode + }Catch { + $module.FailJson("Failed to update organizational unit: $($_.Exception.Message)", $_) + } + } +} + +if ($state -eq "absent") { + # ou exists, delete object + if ($current_ou -and -not $check_mode) { + Try { + # override protected from accidental deletion + $module.Result.extra_args = $onboard_extra_args + Set-ADOrganizationalUnit -Identity "OU=$name,$path" -ProtectedFromAccidentalDeletion $false @onboard_extra_args -Confirm:$False -WhatIf:$check_mode + # check recursive deletion + if ($recursive) { + Remove-ADOrganizationalUnit -Identity "OU=$name,$path" -Confirm:$False -WhatIf:$check_mode -Recursive @onboard_extra_args + }else { + Remove-ADOrganizationalUnit -Identity "OU=$name,$path" -Confirm:$False -WhatIf:$check_mode @onboard_extra_args + } + $module.Result.changed = $true + $module.Diff.after = "" + } Catch { + $module.FailJson("Failed to remove OU: $($_.Exception.Message)", $_) + } + } + $module.ExitJson() +} + +# determine if a change was made + +if (-not $check_mode) { + try{ + $module.Result.extra_args = $extra_args + $new_ou = Get-ADOrganizationalUnit @extra_args | Where-Object { + $_.DistinguishedName -eq "OU=$name,$path" + } + }catch{ + $Module.FailJson("Failed to Get-ADOrganizationalUnit: Line 245 $($_.Exception.Message)", $_) + } + # compare old/new objects + if (-not (Compare-OuObject -Original $current_ou -Updated $new_ou -properties $extra_args.Properties)) { + $module.Result.changed = $true + $module.Result.ou = Get-OuObject -Object $new_ou + $module.Diff.after = Get-OuObject -Object $new_ou + } +} + +# simulate changes +if ($check_mode -and $current_ou) { + $new_ou = @{} + $current_ou.PropertyNames | ForEach-Object { + if ($parms[$_.Name]) { $new_ou[$_.Name] = $parms[$_.Name] } + else { $new_ou[$_.Name] = $_.Value } + } + $module.Diff.after = Get-OuObject -Object $new_ou +} +# simulate new ou created +if ($check_mode -and -not $current_ou) { + $simulated_ou = Get-SimulatedOu -Object $parms + $module.Diff.after = Get-OuObject -Object $simulated_ou +} + +$module.ExitJson() diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py new file mode 100644 index 00000000..009996a9 --- /dev/null +++ b/plugins/modules/win_domain_ou.py @@ -0,0 +1,146 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2020 VMware, Inc. All Rights Reserved. +# SPDX-License-Identifier: GPL-3.0-only +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +DOCUMENTATION = r''' +--- +module: win_domain_ou +short_description: Manage Active Directory Organizational Units +author: Joe Zollo (@joezollo), Larry Lane (@gamethis) +requirements: + - This module requires Windows Server 2012 or Newer +description: + - Manage Active Directory Organizational Units + - Adds, Removes and Modifies Active Directory Organizational Units + - Task should be delegated to a Windows Active Directory Domain Controller +options: + name: + description: + - The name of the Organizational Unit + type: str + required: true + protected: + description: + - Indicates whether to prevent the object from being deleted. When this + l(protected=true), you cannot delete the corresponding object without + changing the value of the property. + type: bool + default: false + path: + description: + - Specifies the X.500 path of the OU or container where the new object is + created. + - defaults to adding ou at base of domain connected to. + type: str + required: false + state: + description: + - Specifies the desired state of the OU. + - When l(state=present) the module will attempt to create the specified + OU if it does not already exist. + - When l(state=absent), the module will remove the specified OU. + - When l(state=absent) and l(recursive=true), the module will remove all + the OU and all child OU's. + type: str + default: present + choices: [ present, absent ] + recursive: + description: + - Removes the OU and any child items it contains. + - You must specify this parameter to remove an OU that is not empty. + type: bool + default: false + domain_server: + description: + - Specifies the Active Directory Domain Services instance to connect to. + - Can be in the form of an FQDN or NetBIOS name. + - If not specified then the value is based on the domain of the computer + running PowerShell. + type: str + domain_username: + description: + - The username to use when interacting with AD. + - If this is not set then the user Ansible used to log in with will be + used instead when using CredSSP or Kerberos with credential delegation. + type: str + domain_password: + description: + - The password for + properties: + type: dict + description: + - Defines specific LDAP properties for the organizational unit. +''' + +EXAMPLES = r''' +- name: Ensure OU is present & protected + community.windows.win_domain_ou: + name: AnsibleFest + state: present + +- name: Ensure OU is present & protected + community.windows.win_domain_ou: + name: EUC Users + path: "DC=euc,DC=vmware,DC=lan" + state: present + protected: true + delegate_to: win-ad1.euc.vmware.lab + +- name: Ensure OU is absent + community.windows.win_domain_ou: + name: EUC Users + path: "DC=euc,DC=vmware,DC=lan" + state: absent + delegate_to: win-ad1.euc.vmware.lab + +- name: Ensure OU is present with specific properties + community.windows.win_domain_ou: + name: WS1Users + path: "CN=EUC Users,DC=euc,DC=vmware,DC=lan" + protected: true + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postal_code: 30189 + delegate_to: win-ad1.euc.vmware.lab + +- name: Ensure OU updated with new properties + community.windows.win_domain_ou: + name: WS1Users + path: DC=euc,DC=vmware,DC=lan + protected: false + properties: + city: Atlanta + state: Georgia + managed_by: jzollo@vmware.com + delegate_to: win-ad1.euc.vmware.lab +''' + +RETURN = r''' +ou: + description: New/Updated organizational unit parameters + returned: When l(state=present) + type: dict + sample: + name: + guid: + distinguished_name: + canonoical_name: + created: + modified: + protected: + properties: + display_name: + description: + city: + street_address: + postal_code: + country: + managed_by: +''' From c170fdaf73d7cfebe50e7e037fe4694731391979 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:48:57 -0500 Subject: [PATCH 17/49] adding aliases --- tests/integration/targets/win_domain_ou/aliases | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/integration/targets/win_domain_ou/aliases diff --git a/tests/integration/targets/win_domain_ou/aliases b/tests/integration/targets/win_domain_ou/aliases new file mode 100644 index 00000000..22f581bf --- /dev/null +++ b/tests/integration/targets/win_domain_ou/aliases @@ -0,0 +1,2 @@ +shippable/windows/group2 +skip/windows/2012 From bb69cbc33dec2071bb5059530b58196da6f751a5 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:52:34 -0500 Subject: [PATCH 18/49] adding defaults --- .../win_domain_ou/defaults/default.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/integration/targets/win_domain_ou/defaults/default.yml diff --git a/tests/integration/targets/win_domain_ou/defaults/default.yml b/tests/integration/targets/win_domain_ou/defaults/default.yml new file mode 100644 index 00000000..62fd907b --- /dev/null +++ b/tests/integration/targets/win_domain_ou/defaults/default.yml @@ -0,0 +1,37 @@ +--- +- name: Ensure AD/DNS roles are installed + ansible.windows.win_feature: + name: + - AD-Domain-Services + - DNS + include_management_tools: true + include_sub_features: true + state: present + +- name: Ensure domain is present + ansible.windows.win_domain: + dns_domain_name: ansible.test + safe_mode_password: password123! + register: ensure_domain + +- name: Reboot + ansible.windows.win_reboot: + when: ensure_domain.changed + +- name: Try Import-Module + ansible.windows.win_shell: | + whoami + try{Import-Module ActiveDirectory} + catch{ + start-sleep -seconds 5 + Import-Module ActiveDirectory + } + ignore_errors: true + register: import_test + +- name: Reboot Again + ansible.windows.win_reboot: + when: import_test is failed + +- name: Run Tests + include_tasks: quick.yml From acb35aade882f525731b05659af566af7e099e2b Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:53:04 -0500 Subject: [PATCH 19/49] Create main.yml --- .../targets/win_domain_ou/defaults/main.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/integration/targets/win_domain_ou/defaults/main.yml diff --git a/tests/integration/targets/win_domain_ou/defaults/main.yml b/tests/integration/targets/win_domain_ou/defaults/main.yml new file mode 100644 index 00000000..5789ed85 --- /dev/null +++ b/tests/integration/targets/win_domain_ou/defaults/main.yml @@ -0,0 +1,12 @@ +--- +win_domain_ou_test_type: default +win_domain_ou_root_path: DC=ansible,DC=test +win_domain_ou_structure: + - path: "{{ win_domain_ou_root_path }}" + name: VMware + - path: "OU=VMware,{{ win_domain_ou_root_path }}" + name: End User Computing + - path: "OU=End User Computing,OU=VMware,{{ win_domain_ou_root_path }}" + name: Workspace ONE Cloud Services + - path: "OU=Workspace ONE Cloud Services,OU=End User Computing,OU=VMware,{{ win_domain_ou_root_path }}" + name: SaaS Development and Enablement From 282ef488b659e4d4a282afbc72c4a6596aecb121 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:53:48 -0500 Subject: [PATCH 20/49] Create default.yml --- .../targets/win_domain_ou/tasks/default.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/integration/targets/win_domain_ou/tasks/default.yml diff --git a/tests/integration/targets/win_domain_ou/tasks/default.yml b/tests/integration/targets/win_domain_ou/tasks/default.yml new file mode 100644 index 00000000..62fd907b --- /dev/null +++ b/tests/integration/targets/win_domain_ou/tasks/default.yml @@ -0,0 +1,37 @@ +--- +- name: Ensure AD/DNS roles are installed + ansible.windows.win_feature: + name: + - AD-Domain-Services + - DNS + include_management_tools: true + include_sub_features: true + state: present + +- name: Ensure domain is present + ansible.windows.win_domain: + dns_domain_name: ansible.test + safe_mode_password: password123! + register: ensure_domain + +- name: Reboot + ansible.windows.win_reboot: + when: ensure_domain.changed + +- name: Try Import-Module + ansible.windows.win_shell: | + whoami + try{Import-Module ActiveDirectory} + catch{ + start-sleep -seconds 5 + Import-Module ActiveDirectory + } + ignore_errors: true + register: import_test + +- name: Reboot Again + ansible.windows.win_reboot: + when: import_test is failed + +- name: Run Tests + include_tasks: quick.yml From 3fe224e1fe822ed702e3aa96362a3ece218ee82f Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:54:03 -0500 Subject: [PATCH 21/49] Create main.yml --- tests/integration/targets/win_domain_ou/tasks/main.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/integration/targets/win_domain_ou/tasks/main.yml diff --git a/tests/integration/targets/win_domain_ou/tasks/main.yml b/tests/integration/targets/win_domain_ou/tasks/main.yml new file mode 100644 index 00000000..e738a3b2 --- /dev/null +++ b/tests/integration/targets/win_domain_ou/tasks/main.yml @@ -0,0 +1,3 @@ +--- +- name: Run the specified test + include_tasks: "{{ win_domain_ou_test_type }}.yml" From c681e2f8a8e2dba00e4328b9141919f186f9a887 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 12:54:20 -0500 Subject: [PATCH 22/49] Create quick.yml --- .../targets/win_domain_ou/tasks/quick.yml | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 tests/integration/targets/win_domain_ou/tasks/quick.yml diff --git a/tests/integration/targets/win_domain_ou/tasks/quick.yml b/tests/integration/targets/win_domain_ou/tasks/quick.yml new file mode 100644 index 00000000..5696e4de --- /dev/null +++ b/tests/integration/targets/win_domain_ou/tasks/quick.yml @@ -0,0 +1,280 @@ +--- +- name: Wait for ADWS + community.windows.win_wait_for_process: + process_name_exact: Microsoft.ActiveDirectory.WebServices + timeout: 120 + sleep: 5 + process_min_count: 1 + +- name: Try Import Again + block: + - name: Try Import-Module + ansible.windows.win_shell: | + whoami + try{Import-Module ActiveDirectory} + catch{ + start-sleep -seconds 5 + Import-Module ActiveDirectory + } + register: import_test2 + rescue: + - name: Try Import-Module + ansible.windows.win_shell: C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\ActiveDirectory.psd1 + register: import_test3 + +- name: Ensure OU is present + community.windows.win_domain_ou: + name: AnsibleFest + register: test1 + failed_when: test1 is not changed + +- name: Ensure OU is present (idempotence check) + community.windows.win_domain_ou: + name: AnsibleFest + register: test1a + failed_when: test1a is changed + +- name: Ensure OU is present + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + register: test2 + failed_when: test2 is not changed + +- name: Ensure OU is present (idempotence check) + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + register: test2a + failed_when: test2a is changed + +- name: Ensure OU has updated properties + community.windows.win_domain_ou: + name: End User Computing + protected: true + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postal_code: 30189 + register: test3 + failed_when: test3 is not changed + +- name: Ensure OU has updated properties (idempotence check) + community.windows.win_domain_ou: + name: End User Computing + protected: true + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postal_code: 30189 + register: test3a + failed_when: test3a is changed + +- name: Ensure OU structure is present + community.windows.win_domain_ou: + name: "{{ item.name }}" + protected: false + path: "{{ item.path }}" + loop: "{{ win_domain_ou_structure }}" + register: test4 + failed_when: test4 is not changed + +- name: Ensure OU structure is present (idempotence check) + community.windows.win_domain_ou: + name: "{{ item.name }}" + protected: false + path: "{{ item.path }}" + loop: "{{ win_domain_ou_structure }}" + register: test4a + failed_when: test4a is changed + +- name: Ensure OU structure is absent, recursive + community.windows.win_domain_ou: + name: VMware + path: "{{ win_domain_ou_root_path }}" + state: absent + recursive: true + register: test5 + failed_when: test5 is not changed + +- name: Ensure OU structure is absent, recursive (idempotence check) + community.windows.win_domain_ou: + name: VMware + path: "{{ win_domain_ou_root_path }}" + state: absent + recursive: true + register: test5a + failed_when: test5a is changed + +- name: Ensure OU is present with specific properties + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + register: test6 + failed_when: test6 is not changed + +- name: Ensure OU is present with specific properties (idempotence check) + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + register: test6a + failed_when: test6a is changed + +- name: Ensure OU is present with specific properties added + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + country: US + description: EUC Business Unit + postal_code: 30189 + register: test7 + failed_when: test7 is not changed + +- name: Ensure OU is present with specific properties added (idempotence check) + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + country: US + description: EUC Business Unit + postal_code: 30189 + register: test7a + failed_when: test7a is changed + +- name: Ensure OU is absent + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test8 + failed_when: test8 is not changed + +- name: Ensure OU is absent (idempotence check) + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test8a + failed_when: test8a is changed + +- name: Ensure OU is absent + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test9 + failed_when: test9 is not changed + +- name: Ensure OU is absent (idempotence check) + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test9a + failed_when: test9a is changed + +- name: Assertions + assert: + that: + - test1a.ou.name == "AnsibleFest" + - test3a.ou.properties.street_address == "1155 Perimeter Center West" + - test7a.ou.properties.country == "US" + - test6a.ou.properties.city == "Sandy Springs" + +- name: Run Check Mode Tests + block: + - name: Ensure OU is present + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + register: test1c + failed_when: test1c is changed + + - name: Ensure OU has updated properties + community.windows.win_domain_ou: + name: End User Computing + protected: true + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postal_code: 30189 + register: test2c + failed_when: test2c is changed + + - name: Ensure OU structure is present + community.windows.win_domain_ou: + name: "{{ item.name }}" + protected: false + path: "{{ item.path }}" + loop: "{{ win_domain_ou_structure }}" + register: test3c + failed_when: test3c is changed + + - name: Ensure OU structure is absent, recursive + community.windows.win_domain_ou: + name: VMware + path: "{{ win_domain_ou_root_path }}" + state: absent + recursive: true + register: test4c + failed_when: test4c is changed + + - name: Ensure OU is present with specific properties + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + street_address: 1155 Perimeter Center West + register: test5c + failed_when: test5c is changed + + - name: Ensure OU is present with specific properties added + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + country: US + description: EUC Business Unit + postal_code: 30189 + register: test6c + failed_when: test6c is changed + + - name: Ensure OU is absent + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test7c + failed_when: test7c is changed + + - name: Ensure OU is absent + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test8c + failed_when: test8c is changed + check_mode: true From fce2ac2170d4da5a747416973bc4bc11c0b7982a Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 13:04:12 -0500 Subject: [PATCH 23/49] fixing doc --- plugins/modules/win_domain_ou.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 009996a9..71793789 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -67,8 +67,14 @@ used instead when using CredSSP or Kerberos with credential delegation. type: str domain_password: + type: str description: - - The password for + - The password for the domain you are accessig + + filter: + type: str + description: filter for lookup of ou. + default: '*' properties: type: dict description: @@ -109,7 +115,7 @@ description: EUC Business Unit postal_code: 30189 delegate_to: win-ad1.euc.vmware.lab - + - name: Ensure OU updated with new properties community.windows.win_domain_ou: name: WS1Users From 1ed27d3710f305b755125af481e82f1f99c089af Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 13:50:27 -0500 Subject: [PATCH 24/49] linting --- plugins/modules/win_domain_ou.ps1 | 9 ++++++--- plugins/modules/win_domain_ou.py | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index b74d559e..9f2e2371 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -49,7 +49,6 @@ if ($module.Params.properties.count -ne 0){ $keyName = "" if ($item.Contains("_")){ $item.Split("_") | Foreach-Object{ - write-host $_ $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() } }else{ @@ -78,7 +77,6 @@ if ($module.Params.properties.count -ne 0){ $keyName = "" if ($item.Contains("_")){ $item.Split("_") | Foreach-Object{ - write-host $_ $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() } }else{ @@ -202,7 +200,12 @@ if ($null -eq $path){ }else{ $module.FailJson("path was null and unable to determine default domain $($_.Exception.Message)", $_) } - $path = $matches.Values[0] + if ($matched){ + $path = $matches.Values[0] + }else{ + $module.FailJson("Unable to find default domain $($_.Exception.Message)", $_) + } +} } # determine if requested OU exist diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 71793789..a70d6442 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -69,8 +69,7 @@ domain_password: type: str description: - - The password for the domain you are accessig - + - The password for the domain you are accessing filter: type: str description: filter for lookup of ou. From c95bbe938825aba4802d6a353a2d370c68075386 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 14:33:48 -0500 Subject: [PATCH 25/49] linted From e7d30e00d32929719bad5533802d4dd7590e42ad Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 14:56:18 -0500 Subject: [PATCH 26/49] more linting --- plugins/modules/win_domain_ou.ps1 | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 9f2e2371..043dedfe 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -14,12 +14,12 @@ $spec = @{ name = @{ type = "str"; required = $true } protected = @{ type = "bool"; default = $false } path = @{ type = "str"; required = $false } - filter = @{type = "str"; default = '*';} + filter = @{type = "str"; default = "*" } recursive = @{ type = "bool"; default = $false } domain_username = @{ type = "str"; } - domain_password = @{ type = "str"; no_log = $true } - domain_server = @{ type = "str"; } - properties = @{ type = "dict";} + domain_password = @{ type = "str"; no_log = $true } + domain_server = @{ type = "str" } + properties = @{ type = "dict" } } required_together = @( ,@('domain_password', 'domain_username') @@ -46,8 +46,8 @@ if ($module.Params.properties.count -ne 0){ $module.Params.properties.Keys | Foreach-Object{ $extra_args.Properties = New-Object Collections.Generic.List[string] $item = $_ - $keyName = "" - if ($item.Contains("_")){ + [string]$keyName + if ( $item.Contains("_") ){ $item.Split("_") | Foreach-Object{ $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() } @@ -107,7 +107,7 @@ Function Get-SimulatedOu { $parms = @{ Name = $Object.name - DistinguishedName = "OU=$($Object.name)," + $Object.path + DistinguishedName = "OU=$($Object.name),$($Object.path)" ProtectedFromAccidentalDeletion = $Object.protected } @@ -206,7 +206,6 @@ if ($null -eq $path){ $module.FailJson("Unable to find default domain $($_.Exception.Message)", $_) } } -} # determine if requested OU exist Try { @@ -215,7 +214,6 @@ Try { $module.Diff.before = Get-OuObject -Object $current_ou $module.Result.ou = $module.Diff.before } Catch { - #$module.FailJson("current_ou error $($_.Exception.Message)", $_) $module.Diff.before = "" $current_ou = $false } @@ -269,7 +267,6 @@ if ($state -eq "absent") { } # determine if a change was made - if (-not $check_mode) { try{ $module.Result.extra_args = $extra_args From 30e7a04c8461441472898c621cf714114047f9f8 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Fri, 30 Jul 2021 15:24:20 -0500 Subject: [PATCH 27/49] fix assertion test --- tests/integration/targets/win_domain_ou/tasks/quick.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/targets/win_domain_ou/tasks/quick.yml b/tests/integration/targets/win_domain_ou/tasks/quick.yml index 5696e4de..e0440bc3 100644 --- a/tests/integration/targets/win_domain_ou/tasks/quick.yml +++ b/tests/integration/targets/win_domain_ou/tasks/quick.yml @@ -194,9 +194,9 @@ assert: that: - test1a.ou.name == "AnsibleFest" - - test3a.ou.properties.street_address == "1155 Perimeter Center West" - - test7a.ou.properties.country == "US" - - test6a.ou.properties.city == "Sandy Springs" + - test3a.ou.street_address == "1155 Perimeter Center West" + - test7a.ou.country == "US" + - test6a.ou.city == "Sandy Springs" - name: Run Check Mode Tests block: From 5b92bf4d63ef95e2456f30e6faded437d5074f66 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 09:45:15 -0500 Subject: [PATCH 28/49] Update win_domain_ou.py --- plugins/modules/win_domain_ou.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index a70d6442..1a319172 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -9,7 +9,10 @@ --- module: win_domain_ou short_description: Manage Active Directory Organizational Units -author: Joe Zollo (@joezollo), Larry Lane (@gamethis) +version_added: 1.7.0 +author: +- Joe Zollo (@joezollo) +- Larry Lane (@gamethis) requirements: - This module requires Windows Server 2012 or Newer description: @@ -77,7 +80,11 @@ properties: type: dict description: - - Defines specific LDAP properties for the organizational unit. + - Free form dict of properties for the organizational unit. + - Key should be in camelCase. + - syntax is Key: Value. ie `City: Gainesville` + - For more information on available properties see https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adorganizationalunit. + ''' EXAMPLES = r''' @@ -109,10 +116,10 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + StreetAddress: 1155 Perimeter Center West country: US description: EUC Business Unit - postal_code: 30189 + postalCode: 30189 delegate_to: win-ad1.euc.vmware.lab - name: Ensure OU updated with new properties From dc33c749250a764fd092d1f1e6f565a9094ed482 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 09:46:10 -0500 Subject: [PATCH 29/49] reoved use of snakecase conversions --- plugins/modules/win_domain_ou.ps1 | 70 +------------------------------ 1 file changed, 2 insertions(+), 68 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 043dedfe..69976f62 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -45,16 +45,7 @@ if ($module.Params.properties.count -ne 0){ $extra_args.Properties = "" $module.Params.properties.Keys | Foreach-Object{ $extra_args.Properties = New-Object Collections.Generic.List[string] - $item = $_ - [string]$keyName - if ( $item.Contains("_") ){ - $item.Split("_") | Foreach-Object{ - $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() - } - }else{ - $keyName = $item.substring(0,1).toupper() + $item.substring(1).tolower() - } - $extra_args.Properties.Add($keyName) + $extra_args.Properties.Add($_) } }else{ $extra_args.Properties = '*' @@ -73,16 +64,7 @@ $recursive = $module.Params.recursive $parms = @{} if ($module.Params.properties.count -ne 0){ $module.Params.properties.Keys | ForEach-Object{ - $item = $_ - $keyName = "" - if ($item.Contains("_")){ - $item.Split("_") | Foreach-Object{ - $keyName = $keyname + $_.substring(0,1).toupper() + $_.substring(1).tolower() - } - }else{ - $keyName = $item.substring(0,1).toupper() + $item.substring(1).tolower() - } - $parms.Add($keyName,$module.Params.properties.Item($_)) + $parms.Add($_,$module.Params.properties.Item($_)) } } $module.Result.params = $parms @@ -124,57 +106,9 @@ Function Get-SimulatedOu { # convert to psobject & return [PSCustomObject]$parms } -function Convert-ObjectToSnakeCase { - <# - .SYNOPSIS - Converts an object with CamelCase properties to a dictionary with snake_case keys. - Works in the spirit of and depends on the existing CamelConversion module util. - #> - [CmdletBinding()] - param( - [Parameter(Mandatory=$true,ValueFromPipeline=$true)] - [OutputType([System.Collections.Specialized.OrderedDictionary])] - [Object] - $InputObject , - - [Parameter()] - [Switch] - $NoRecurse , - - [Parameter()] - [Switch] - $OmitNull - ) - - Process { - $result = [Ordered]@{} - foreach ($property in $InputObject.PSObject.Properties) { - $value = $property.Value - if (-not $NoRecurse -and $value -is [System.Collections.IDictionary]) { - $value = Convert-DictToSnakeCase -dict $value - } - elseif (-not $NoRecurse -and ($value -is [Array] -or $value -is [System.Collections.ArrayList])) { - $value = Convert-ListToSnakeCase -list $value - } - elseif ($null -eq $value) { - if ($OmitNull) { - continue - } - } - elseif (-not $NoRecurse -and $value -isnot [System.ValueType] -and $value -isnot [string]) { - $value = Convert-ObjectToSnakeCase -InputObject $value - } - - $name = Convert-StringToSnakeCase -string $property.Name - $result[$name] = $value - } - $result - } -} Function Get-OuObject { Param([PSObject]$Object) $obj = $Object | Select-Object -Property * -ExcludeProperty ObjectGUID,nTSecurityDescriptor - $obj = Convert-ObjectToSnakeCase -InputObject $obj -NoRecurse try{$obj.object_guid = $Object.ObjectGUID} catch{$module.FailJson("Adding objectGUid $($_.Exception.Message)", $_)} return $obj From b92c1f0f6e5cc903104aa3cc32b5648f8551993f Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 09:48:58 -0500 Subject: [PATCH 30/49] Corrrected test that used snakecase --- .../integration/targets/win_domain_ou/tasks/quick.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/integration/targets/win_domain_ou/tasks/quick.yml b/tests/integration/targets/win_domain_ou/tasks/quick.yml index e0440bc3..be27dd69 100644 --- a/tests/integration/targets/win_domain_ou/tasks/quick.yml +++ b/tests/integration/targets/win_domain_ou/tasks/quick.yml @@ -143,7 +143,7 @@ properties: country: US description: EUC Business Unit - postal_code: 30189 + postalCode: 30189 register: test7 failed_when: test7 is not changed @@ -154,7 +154,7 @@ properties: country: US description: EUC Business Unit - postal_code: 30189 + postalCode: 30189 register: test7a failed_when: test7a is changed @@ -218,7 +218,7 @@ street_address: 1155 Perimeter Center West country: US description: EUC Business Unit - postal_code: 30189 + postalCode: 30189 register: test2c failed_when: test2c is changed @@ -247,7 +247,7 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + streetAddress: 1155 Perimeter Center West register: test5c failed_when: test5c is changed @@ -258,7 +258,7 @@ properties: country: US description: EUC Business Unit - postal_code: 30189 + postalCode: 30189 register: test6c failed_when: test6c is changed From 1aad258ff65ab680410f29e68db083779b581ace Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 13:46:50 -0500 Subject: [PATCH 31/49] doc update --- plugins/modules/win_domain_ou.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 1a319172..8dbf037c 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -49,7 +49,7 @@ the OU and all child OU's. type: str default: present - choices: [ present, absent ] + choices: [ 'present', 'absent' ] recursive: description: - Removes the OU and any child items it contains. @@ -58,32 +58,32 @@ default: false domain_server: description: - - Specifies the Active Directory Domain Services instance to connect to. - - Can be in the form of an FQDN or NetBIOS name. - - If not specified then the value is based on the domain of the computer - running PowerShell. + - Specifies the Active Directory Domain Services instance to connect to. + - Can be in the form of an FQDN or NetBIOS name. + - If not specified then the value is based on the domain of the computer + running PowerShell. type: str domain_username: description: - - The username to use when interacting with AD. - - If this is not set then the user Ansible used to log in with will be - used instead when using CredSSP or Kerberos with credential delegation. + - The username to use when interacting with AD. + - If this is not set then the user Ansible used to log in with will be + used instead when using CredSSP or Kerberos with credential delegation. type: str domain_password: - type: str description: - - The password for the domain you are accessing - filter: + - The password for the domain you are accessing type: str + filter: description: filter for lookup of ou. + type: str default: '*' properties: type: dict description: - Free form dict of properties for the organizational unit. - Key should be in camelCase. - - syntax is Key: Value. ie `City: Gainesville` - - For more information on available properties see https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adorganizationalunit. + - For more information on available properties see + https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adorganizationalunit. ''' From 7e034410287742739f03b1da271c2ac517bc70fd Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 13:47:38 -0500 Subject: [PATCH 32/49] linting fix --- plugins/modules/win_domain_ou.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 8dbf037c..1fe03f92 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -84,7 +84,6 @@ - Key should be in camelCase. - For more information on available properties see https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adorganizationalunit. - ''' EXAMPLES = r''' From ad497ae934d3ec2148fb5d620a9bc20ed6ee3a9f Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 13:51:58 -0500 Subject: [PATCH 33/49] pep8 fix --- plugins/modules/win_domain_ou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 1fe03f92..8c0b463d 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -82,7 +82,7 @@ description: - Free form dict of properties for the organizational unit. - Key should be in camelCase. - - For more information on available properties see + - For more information on available properties see https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adorganizationalunit. ''' From 9320fe612235bd98aceeb966edb2c951356cdd72 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 14:04:52 -0500 Subject: [PATCH 34/49] fixing error --- plugins/modules/win_domain_ou.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 69976f62..3fc83fbb 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -109,7 +109,7 @@ Function Get-SimulatedOu { Function Get-OuObject { Param([PSObject]$Object) $obj = $Object | Select-Object -Property * -ExcludeProperty ObjectGUID,nTSecurityDescriptor - try{$obj.object_guid = $Object.ObjectGUID} + try{$obj.ObjectGUID = $Object.ObjectGUID} catch{$module.FailJson("Adding objectGUid $($_.Exception.Message)", $_)} return $obj } From 83e4d09d5cc63d3a4b8aa0e14ffb1af008cb1b92 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 14:54:01 -0500 Subject: [PATCH 35/49] Update win_domain_ou.ps1 --- plugins/modules/win_domain_ou.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 3fc83fbb..3be94bdf 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -14,7 +14,7 @@ $spec = @{ name = @{ type = "str"; required = $true } protected = @{ type = "bool"; default = $false } path = @{ type = "str"; required = $false } - filter = @{type = "str"; default = "*" } + filter = @{type = "str"; required = $false } recursive = @{ type = "bool"; default = $false } domain_username = @{ type = "str"; } domain_password = @{ type = "str"; no_log = $true } @@ -51,7 +51,9 @@ if ($module.Params.properties.count -ne 0){ $extra_args.Properties = '*' } -$extra_args.Filter = $module.Params.filter +if ($null -ne $module.Params.filter){ + $extra_args.Filter = $module.Params.filter +} $check_mode = $module.CheckMode $name = $module.Params.name @@ -108,9 +110,7 @@ Function Get-SimulatedOu { } Function Get-OuObject { Param([PSObject]$Object) - $obj = $Object | Select-Object -Property * -ExcludeProperty ObjectGUID,nTSecurityDescriptor - try{$obj.ObjectGUID = $Object.ObjectGUID} - catch{$module.FailJson("Adding objectGUid $($_.Exception.Message)", $_)} + $obj = $Object | Select-Object -Property * -ExcludeProperty nTSecurityDescriptor return $obj } From bdee8885fa6e132aefbad12c7341594886993d89 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 14:54:35 -0500 Subject: [PATCH 36/49] Update win_domain_ou.py --- plugins/modules/win_domain_ou.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 8c0b463d..7124e3cf 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -76,7 +76,6 @@ filter: description: filter for lookup of ou. type: str - default: '*' properties: type: dict description: From 61ffa7b952e0d9dc3c0d8c5872165be01051d162 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 16:51:57 -0500 Subject: [PATCH 37/49] fixing filter --- plugins/modules/win_domain_ou.ps1 | 9 ++++---- plugins/modules/win_domain_ou.py | 34 ++++++++++++++----------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 3be94bdf..0db66a90 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -14,7 +14,7 @@ $spec = @{ name = @{ type = "str"; required = $true } protected = @{ type = "bool"; default = $false } path = @{ type = "str"; required = $false } - filter = @{type = "str"; required = $false } + filter = @{type = "str"; default = '*' } recursive = @{ type = "bool"; default = $false } domain_username = @{ type = "str"; } domain_password = @{ type = "str"; no_log = $true } @@ -51,9 +51,8 @@ if ($module.Params.properties.count -ne 0){ $extra_args.Properties = '*' } -if ($null -ne $module.Params.filter){ - $extra_args.Filter = $module.Params.filter -} + +$extra_args.Filter = $module.Params.filter $check_mode = $module.CheckMode $name = $module.Params.name @@ -111,6 +110,8 @@ Function Get-SimulatedOu { Function Get-OuObject { Param([PSObject]$Object) $obj = $Object | Select-Object -Property * -ExcludeProperty nTSecurityDescriptor + try{$obj.ObjectGUID = $Object.ObjectGUID} + catch{$module.FailJson("Adding objectGUid Line:112 $($_.Exception.Message)", $_)} return $obj } diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 7124e3cf..06edcfc8 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -9,10 +9,8 @@ --- module: win_domain_ou short_description: Manage Active Directory Organizational Units +author: ['Joe Zollo (@joezollo)', 'Larry Lane (@gamethis)'] version_added: 1.7.0 -author: -- Joe Zollo (@joezollo) -- Larry Lane (@gamethis) requirements: - This module requires Windows Server 2012 or Newer description: @@ -49,7 +47,7 @@ the OU and all child OU's. type: str default: present - choices: [ 'present', 'absent' ] + choices: [ present, absent ] recursive: description: - Removes the OU and any child items it contains. @@ -58,31 +56,29 @@ default: false domain_server: description: - - Specifies the Active Directory Domain Services instance to connect to. - - Can be in the form of an FQDN or NetBIOS name. - - If not specified then the value is based on the domain of the computer - running PowerShell. + - Specifies the Active Directory Domain Services instance to connect to. + - Can be in the form of an FQDN or NetBIOS name. + - If not specified then the value is based on the domain of the computer + running PowerShell. type: str domain_username: description: - - The username to use when interacting with AD. - - If this is not set then the user Ansible used to log in with will be - used instead when using CredSSP or Kerberos with credential delegation. + - The username to use when interacting with AD. + - If this is not set then the user Ansible used to log in with will be + used instead when using CredSSP or Kerberos with credential delegation. type: str domain_password: - description: - - The password for the domain you are accessing type: str + description: + - The password for the domain you are accessing filter: - description: filter for lookup of ou. type: str + description: filter for lookup of ou. + default: '*' properties: type: dict description: - Free form dict of properties for the organizational unit. - - Key should be in camelCase. - - For more information on available properties see - https://docs.microsoft.com/en-us/powershell/module/activedirectory/set-adorganizationalunit. ''' EXAMPLES = r''' @@ -114,10 +110,10 @@ properties: city: Sandy Springs state: Georgia - StreetAddress: 1155 Perimeter Center West + street_address: 1155 Perimeter Center West country: US description: EUC Business Unit - postalCode: 30189 + postal_code: 30189 delegate_to: win-ad1.euc.vmware.lab - name: Ensure OU updated with new properties From 6e5c32d883dc5e9ecc629cdd6efee96862f78b26 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 17:05:39 -0500 Subject: [PATCH 38/49] Add files via upload --- plugins/modules/win_domain_ou.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 0db66a90..599ec771 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -110,8 +110,6 @@ Function Get-SimulatedOu { Function Get-OuObject { Param([PSObject]$Object) $obj = $Object | Select-Object -Property * -ExcludeProperty nTSecurityDescriptor - try{$obj.ObjectGUID = $Object.ObjectGUID} - catch{$module.FailJson("Adding objectGUid Line:112 $($_.Exception.Message)", $_)} return $obj } From 6357754f9721171208c5b89b531346e0936ccdd1 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Mon, 30 Aug 2021 17:26:58 -0500 Subject: [PATCH 39/49] fixing change check --- plugins/modules/win_domain_ou.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 599ec771..80235ffa 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -82,7 +82,7 @@ Function Compare-OuObject { }else{ $x = Compare-Object -ReferenceObject $Original -DifferenceObject $Updated } - $x.Count -eq 0 + return $x.Count -eq 0 } Function Get-SimulatedOu { @@ -159,7 +159,7 @@ if ($state -eq "present") { Try { $module.Result.params = $parms $module.Result.extra_args = $onboard_extra_args - New-ADOrganizationalUnit @parms @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode + $current_ou = New-ADOrganizationalUnit @parms @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode }Catch { $module.FailJson("Failed to create organizational unit: $($_.Exception.Message)", $_) } @@ -210,11 +210,11 @@ if (-not $check_mode) { $Module.FailJson("Failed to Get-ADOrganizationalUnit: Line 245 $($_.Exception.Message)", $_) } # compare old/new objects + $module.Result.ou = Get-OuObject -Object $current_ou + $module.Diff.after = Get-OuObject -Object $new_ou if (-not (Compare-OuObject -Original $current_ou -Updated $new_ou -properties $extra_args.Properties)) { $module.Result.changed = $true - $module.Result.ou = Get-OuObject -Object $new_ou - $module.Diff.after = Get-OuObject -Object $new_ou - } + }else{} } # simulate changes From 03bb2e260fec2e603404d096f632c2076c35f6a6 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Wed, 15 Sep 2021 17:34:29 -0500 Subject: [PATCH 40/49] changes to fix errors --- plugins/modules/win_domain_ou.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 80235ffa..3a04eaba 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -42,16 +42,16 @@ if ($null -ne $module.Params.domain_server) { $onboard_extra_args.Server = $module.Params.domain_server } if ($module.Params.properties.count -ne 0){ - $extra_args.Properties = "" + $Properties = New-Object Collections.Generic.List[string] $module.Params.properties.Keys | Foreach-Object{ - $extra_args.Properties = New-Object Collections.Generic.List[string] - $extra_args.Properties.Add($_) + $Properties.Add($_) } + $extra_args.Properties = $Properties }else{ $extra_args.Properties = '*' + $Properties = '*' } - $extra_args.Filter = $module.Params.filter $check_mode = $module.CheckMode @@ -61,6 +61,7 @@ $path = $module.Params.path $state = $module.Params.state $recursive = $module.Params.recursive +# setup Dynamic Params # setup Dynamic Params $parms = @{} if ($module.Params.properties.count -ne 0){ @@ -159,7 +160,7 @@ if ($state -eq "present") { Try { $module.Result.params = $parms $module.Result.extra_args = $onboard_extra_args - $current_ou = New-ADOrganizationalUnit @parms @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode + New-ADOrganizationalUnit @parms @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode }Catch { $module.FailJson("Failed to create organizational unit: $($_.Exception.Message)", $_) } From 2dfb90da31355fee54d8baf96403b817ebf408a1 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 09:45:18 -0500 Subject: [PATCH 41/49] fix the module --- plugins/modules/win_domain_ou.ps1 | 104 ++++++++++++++++-------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 3a04eaba..827677fd 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -54,7 +54,6 @@ if ($module.Params.properties.count -ne 0){ $extra_args.Filter = $module.Params.filter $check_mode = $module.CheckMode - $name = $module.Params.name $protected = $module.Params.protected $path = $module.Params.path @@ -62,24 +61,32 @@ $state = $module.Params.state $recursive = $module.Params.recursive # setup Dynamic Params -# setup Dynamic Params -$parms = @{} +$params = @{} if ($module.Params.properties.count -ne 0){ $module.Params.properties.Keys | ForEach-Object{ - $parms.Add($_,$module.Params.properties.Item($_)) + $params.Add($_,$module.Params.properties.Item($_)) } } -$module.Result.params = $parms +# capture settings to know what we are doing +$module.Result.params = $params +$module.Result.extra_args = $extra_args +$module.Result.onboard_extra_args = $onboard_extra_args +$module.Result.properties = $properties Function Compare-OuObject { Param( [PSObject]$Original, [PSObject]$Updated, - [string]$properties + $properties ) - if ($Original -eq $false) { return $false } + if (($Null -eq $Original) -or ($Original -eq $false)) { return $false } if ($properties -ne '*'){ $x = Compare-Object -ReferenceObject $Original -DifferenceObject $Updated -Property $properties + #$module.Result.original = $Original | ConvertTo-Json -Compress + #$module.Result.updated = $Updated | ConvertTo-Json -Compress + #$module.Result.compare_properties = $properties + #$module.FailJson("Testing: failed compare $($x.count) $($properties.GetType().Name)") + }else{ $x = Compare-Object -ReferenceObject $Original -DifferenceObject $Updated } @@ -88,59 +95,56 @@ Function Compare-OuObject { Function Get-SimulatedOu { Param($Object) - - $parms = @{ + $params = @{ Name = $Object.name DistinguishedName = "OU=$($Object.name),$($Object.path)" ProtectedFromAccidentalDeletion = $Object.protected } - if ($Object.properties) { - if ($Object.properties.description) { $parms.Description = $Object.properties.description } - if ($Object.properties.city) { $parms.City = $Object.properties.city } - if ($Object.properties.state) { $parms.State = $Object.properties.state } - if ($Object.properties.street_address) { $parms.StreetAddress = $Object.properties.street_address } - if ($Object.properties.postal_code) { $parms.PostalCode = $Object.properties.postal_code } - if ($Object.properties.country) { $parms.Country = $Object.properties.country } - if ($Object.properties.managed_by) { $parms.ManagedBy = $Object.properties.managed_by } + if ($Object.properties.description) { $params.Description = $Object.properties.description } + if ($Object.properties.city) { $params.City = $Object.properties.city } + if ($Object.properties.state) { $params.State = $Object.properties.state } + if ($Object.properties.street_address) { $params.StreetAddress = $Object.properties.street_address } + if ($Object.properties.postal_code) { $params.PostalCode = $Object.properties.postal_code } + if ($Object.properties.country) { $params.Country = $Object.properties.country } + if ($Object.properties.managed_by) { $params.ManagedBy = $Object.properties.managed_by } } - # convert to psobject & return - [PSCustomObject]$parms + [PSCustomObject]$params } + Function Get-OuObject { Param([PSObject]$Object) - $obj = $Object | Select-Object -Property * -ExcludeProperty nTSecurityDescriptor + $obj = $Object | Select-Object -Property * -ExcludeProperty nTSecurityDescriptor | ConvertTo-Json -Depth 1 | ConvertFrom-Json return $obj } # attempt import of module Try { Import-Module ActiveDirectory } -Catch { $module.FailJson("The ActiveDirectory module failed to load properly: $($_.Exception.Message)", $_) } +Catch { $module.FailJson("Line 124: The ActiveDirectory module failed to load properly: $($_.Exception.Message)", $_) } Try{ - $module.Result.extra_args = $extra_args $all_ous = Get-ADOrganizationalUnit @extra_args -}Catch{$module.FailJson("Line 191: Get-ADOrganizationalUnit failed: $($_.Exception.Message)", $_) } - +}Catch{$module.FailJson("Line 128: Get-ADOrganizationalUnit failed: $($_.Exception.Message)", $_) } # set path if not defined to base domain if ($null -eq $path){ if ($($all_ous | Measure-Object | Select-Object -ExpandProperty Count) -eq 1){ $matched = $all_ous.DistinguishedName -match "DC=.+" - }elseif ($($all_ous | Measure-Object | Select-Object -ExpandProperty Count) -gt 1) { $matched = $all_ous[0].DistinguishedName -match "DC=.+" }else{ - $module.FailJson("path was null and unable to determine default domain $($_.Exception.Message)", $_) + $module.FailJson("Line 137: Path was null and unable to determine default domain $($_.Exception.Message)", $_) } if ($matched){ - $path = $matches.Values[0] + $path = $matches.Values[0] }else{ - $module.FailJson("Unable to find default domain $($_.Exception.Message)", $_) + $module.FailJson("Line 142: Unable to find default domain $($_.Exception.Message)", $_) } } +$module.Result.path = $path + # determine if requested OU exist Try { $current_ou = $all_ous | Where-Object { @@ -151,29 +155,26 @@ Try { $module.Diff.before = "" $current_ou = $false } - if ($state -eq "present") { # ou does not exist, create object if(-not $current_ou) { - $parms.Name = $name - $parms.Path = $path + $params.Name = $name + $params.Path = $path + $module.Result.params = $params Try { - $module.Result.params = $parms - $module.Result.extra_args = $onboard_extra_args - New-ADOrganizationalUnit @parms @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode + New-ADOrganizationalUnit @params @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode }Catch { - $module.FailJson("Failed to create organizational unit: $($_.Exception.Message)", $_) + $module.FailJson("Line 167: Failed to create organizational unit: $($_.Exception.Message)", $_) } + $module.Result.Changed = $true } # ou exists, update object if ($current_ou) { Try { - $module.Result.params = $parms - $module.Result.extra_args = $onboard_extra_args - Set-ADOrganizationalUnit -Identity "OU=$name,$path" @parms @onboard_extra_args -WhatIf:$check_mode + Set-ADOrganizationalUnit -Identity "OU=$name,$path" @params @onboard_extra_args -WhatIf:$check_mode }Catch { - $module.FailJson("Failed to update organizational unit: $($_.Exception.Message)", $_) + $module.FailJson("Line 177: Failed to update organizational unit: $($_.Exception.Message)", $_) } } } @@ -183,19 +184,22 @@ if ($state -eq "absent") { if ($current_ou -and -not $check_mode) { Try { # override protected from accidental deletion - $module.Result.extra_args = $onboard_extra_args Set-ADOrganizationalUnit -Identity "OU=$name,$path" -ProtectedFromAccidentalDeletion $false @onboard_extra_args -Confirm:$False -WhatIf:$check_mode + }Catch{ + $module.FailJson("Line 184: Failed to remove ProtectedFromAccidentalDeletion Lock: $($_.Exception.Message)", $_) + } + try{ # check recursive deletion if ($recursive) { Remove-ADOrganizationalUnit -Identity "OU=$name,$path" -Confirm:$False -WhatIf:$check_mode -Recursive @onboard_extra_args }else { Remove-ADOrganizationalUnit -Identity "OU=$name,$path" -Confirm:$False -WhatIf:$check_mode @onboard_extra_args } - $module.Result.changed = $true $module.Diff.after = "" } Catch { - $module.FailJson("Failed to remove OU: $($_.Exception.Message)", $_) + $module.FailJson("Line 200: Failed to remove OU: $($_.Exception.Message)", $_) } + $module.Result.changed = $true } $module.ExitJson() } @@ -208,28 +212,30 @@ if (-not $check_mode) { $_.DistinguishedName -eq "OU=$name,$path" } }catch{ - $Module.FailJson("Failed to Get-ADOrganizationalUnit: Line 245 $($_.Exception.Message)", $_) + $module.FailJson("Line 215: Failed to Get-ADOrganizationalUnit: $($_.Exception.Message)", $_) } - # compare old/new objects - $module.Result.ou = Get-OuObject -Object $current_ou + $module.Diff.after = Get-OuObject -Object $new_ou - if (-not (Compare-OuObject -Original $current_ou -Updated $new_ou -properties $extra_args.Properties)) { + $module.Result.ou = $module.Diff.after + # compare old/new objects + if(-not (Compare-OuObject -Original $module.Diff.before -Updated $module.Diff.after -properties $module.Result.extra_args.Properties)) { $module.Result.changed = $true - }else{} + } } # simulate changes if ($check_mode -and $current_ou) { $new_ou = @{} $current_ou.PropertyNames | ForEach-Object { - if ($parms[$_.Name]) { $new_ou[$_.Name] = $parms[$_.Name] } + if ($params[$_.Name]) { $new_ou[$_.Name] = $params[$_.Name] } else { $new_ou[$_.Name] = $_.Value } } $module.Diff.after = Get-OuObject -Object $new_ou + $module.Result.ou = $module.Diff.after } # simulate new ou created if ($check_mode -and -not $current_ou) { - $simulated_ou = Get-SimulatedOu -Object $parms + $simulated_ou = Get-SimulatedOu -Object $params $module.Diff.after = Get-OuObject -Object $simulated_ou } From d601269b3c19f10a1afcf92b14997578ce6de7b6 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 09:46:13 -0500 Subject: [PATCH 42/49] fixed tests --- .../targets/win_domain_ou/tasks/default.yml | 5 +- .../targets/win_domain_ou/tasks/main.yml | 3 + .../targets/win_domain_ou/tasks/tests.yml | 284 ++++++++++++++++++ 3 files changed, 288 insertions(+), 4 deletions(-) create mode 100644 tests/integration/targets/win_domain_ou/tasks/tests.yml diff --git a/tests/integration/targets/win_domain_ou/tasks/default.yml b/tests/integration/targets/win_domain_ou/tasks/default.yml index 62fd907b..864e7346 100644 --- a/tests/integration/targets/win_domain_ou/tasks/default.yml +++ b/tests/integration/targets/win_domain_ou/tasks/default.yml @@ -23,7 +23,7 @@ whoami try{Import-Module ActiveDirectory} catch{ - start-sleep -seconds 5 + start-sleep -seconds 10 Import-Module ActiveDirectory } ignore_errors: true @@ -32,6 +32,3 @@ - name: Reboot Again ansible.windows.win_reboot: when: import_test is failed - -- name: Run Tests - include_tasks: quick.yml diff --git a/tests/integration/targets/win_domain_ou/tasks/main.yml b/tests/integration/targets/win_domain_ou/tasks/main.yml index e738a3b2..13b8d553 100644 --- a/tests/integration/targets/win_domain_ou/tasks/main.yml +++ b/tests/integration/targets/win_domain_ou/tasks/main.yml @@ -1,3 +1,6 @@ --- - name: Run the specified test include_tasks: "{{ win_domain_ou_test_type }}.yml" + +- name: Run Tests + import_tasks: tests.yml \ No newline at end of file diff --git a/tests/integration/targets/win_domain_ou/tasks/tests.yml b/tests/integration/targets/win_domain_ou/tasks/tests.yml new file mode 100644 index 00000000..634d2d94 --- /dev/null +++ b/tests/integration/targets/win_domain_ou/tasks/tests.yml @@ -0,0 +1,284 @@ +--- +- name: Wait for ADWS + community.windows.win_wait_for_process: + process_name_exact: Microsoft.ActiveDirectory.WebServices + timeout: 120 + sleep: 5 + process_min_count: 1 + +- name: Try Import Again + block: + - name: Try Import-Module + ansible.windows.win_shell: | + whoami + try{Import-Module ActiveDirectory} + catch{ + start-sleep -seconds 5 + Import-Module ActiveDirectory + } + register: import_test2 + rescue: + - name: Try Import-Module + ansible.windows.win_shell: C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\ActiveDirectory.psd1 + register: import_test3 + +- name: Ensure OU is present + community.windows.win_domain_ou: + name: AnsibleFest + register: test1 + failed_when: test1 is not changed + +- name: Ensure OU is present (idempotence check) + community.windows.win_domain_ou: + name: AnsibleFest + register: test1a + failed_when: test1a is changed + +- name: Ensure OU is present with path + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + register: test2 + failed_when: test2 is not changed + +- name: Ensure OU is present with path (idempotence check) + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + register: test2a + failed_when: test2a is changed + +- name: Ensure OU has updated properties + community.windows.win_domain_ou: + name: End User Computing + protected: true + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + streetaddress: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postalcode: 30189 + register: test3 + failed_when: test3 is not changed + +- name: Ensure OU has updated properties (idempotence check) + community.windows.win_domain_ou: + name: End User Computing + protected: true + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + streetaddress: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postalcode: 30189 + register: test3a + failed_when: test3a is changed + +- name: Ensure OU structure is present + community.windows.win_domain_ou: + name: "{{ item.name }}" + protected: false + path: "{{ item.path }}" + loop: "{{ win_domain_ou_structure }}" + register: test4 + failed_when: test4 is not changed + +- name: Ensure OU structure is present (idempotence check) + community.windows.win_domain_ou: + name: "{{ item.name }}" + protected: false + path: "{{ item.path }}" + loop: "{{ win_domain_ou_structure }}" + register: test4a + failed_when: test4a is changed + +- name: Ensure OU structure is absent, recursive + community.windows.win_domain_ou: + name: VMware + path: "{{ win_domain_ou_root_path }}" + state: absent + recursive: true + register: test5 + failed_when: test5 is not changed + +- name: Ensure OU structure is absent, recursive (idempotence check) + community.windows.win_domain_ou: + name: VMware + path: "{{ win_domain_ou_root_path }}" + state: absent + recursive: true + register: test5a + failed_when: test5a is changed + +- name: Ensure OU is present with specific properties + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + streetaddress: 1155 Perimeter Center West + register: test6 + failed_when: test6 is not changed + +- name: Ensure OU is present with specific properties (idempotence check) + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + streetaddress: 1155 Perimeter Center West + register: test6a + failed_when: test6a is changed + +- name: Ensure OU is present with specific properties added + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + country: US + description: EUC Business Unit + postalcode: 30189 + register: test7 + failed_when: test7 is not changed + +- name: Ensure OU is present with specific properties added (idempotence check) + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + country: US + description: EUC Business Unit + postalcode: 30189 + register: test7a + failed_when: test7a is changed + +- name: Ensure OU is absent + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test8 + failed_when: test8 is not changed + +- name: Ensure OU is absent (idempotence check) + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test8a + failed_when: test8a is changed + +- name: Ensure OU is absent + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test9 + failed_when: test9 is not changed + +- name: Ensure OU is absent (idempotence check) + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test9a + failed_when: test9a is changed + +- name: debug + ansible.builtin.debug: + var: test1a.ou.Name + +- name: Assertions + assert: + that: + - test1a.ou.Name == "AnsibleFest" + - test3a.ou.StreetAddress == "1155 Perimeter Center West" + - test7a.ou.Country == "US" + - test6a.ou.City == "Sandy Springs" + +- name: Run Check Mode Tests + block: + - name: Ensure OU is present + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + register: test1c + failed_when: test1c is changed + + - name: Ensure OU has updated properties + community.windows.win_domain_ou: + name: End User Computing + protected: true + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + streetaddress: 1155 Perimeter Center West + country: US + description: EUC Business Unit + postalcode: 30189 + register: test2c + failed_when: test2c is changed + + - name: Ensure OU structure is present + community.windows.win_domain_ou: + name: "{{ item.name }}" + protected: false + path: "{{ item.path }}" + loop: "{{ win_domain_ou_structure }}" + register: test3c + failed_when: test3c is changed + + - name: Ensure OU structure is absent, recursive + community.windows.win_domain_ou: + name: VMware + path: "{{ win_domain_ou_root_path }}" + state: absent + recursive: true + register: test4c + failed_when: test4c is changed + + - name: Ensure OU is present with specific properties + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + city: Sandy Springs + state: Georgia + streetaddress: 1155 Perimeter Center West + register: test5c + failed_when: test5c is changed + + - name: Ensure OU is present with specific properties added + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + properties: + country: US + description: EUC Business Unit + postalcode: 30189 + register: test6c + failed_when: test6c is changed + + - name: Ensure OU is absent + community.windows.win_domain_ou: + name: End User Computing + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test7c + failed_when: test7c is changed + + - name: Ensure OU is absent + community.windows.win_domain_ou: + name: VMW Atlanta + path: "{{ win_domain_ou_root_path }}" + state: absent + register: test8c + failed_when: test8c is changed + check_mode: true From bd501cbae2ca0e02d88b4fcb89b3f63ab144e3d3 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 10:20:13 -0500 Subject: [PATCH 43/49] Add files via upload --- plugins/modules/win_domain_ou.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 827677fd..902141cb 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -137,7 +137,7 @@ if ($null -eq $path){ $module.FailJson("Line 137: Path was null and unable to determine default domain $($_.Exception.Message)", $_) } if ($matched){ - $path = $matches.Values[0] + $path = $matches.Values[0] }else{ $module.FailJson("Line 142: Unable to find default domain $($_.Exception.Message)", $_) } @@ -214,7 +214,7 @@ if (-not $check_mode) { }catch{ $module.FailJson("Line 215: Failed to Get-ADOrganizationalUnit: $($_.Exception.Message)", $_) } - + $module.Diff.after = Get-OuObject -Object $new_ou $module.Result.ou = $module.Diff.after # compare old/new objects From cef15d1a1860eb5a1cab47678fa320c07a067f37 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 18:04:23 -0500 Subject: [PATCH 44/49] addressing changes requested --- plugins/modules/win_domain_ou.ps1 | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index 902141cb..bd4dffec 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -5,7 +5,6 @@ # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) #AnsibleRequires -CSharpUtil Ansible.Basic -#Requires -Module Ansible.ModuleUtils.CamelConversion #Requires -Module ActiveDirectory $spec = @{ @@ -121,11 +120,11 @@ Function Get-OuObject { # attempt import of module Try { Import-Module ActiveDirectory } -Catch { $module.FailJson("Line 124: The ActiveDirectory module failed to load properly: $($_.Exception.Message)", $_) } +Catch { $module.FailJson("The ActiveDirectory module failed to load properly: $($_.Exception.Message)", $_) } Try{ $all_ous = Get-ADOrganizationalUnit @extra_args -}Catch{$module.FailJson("Line 128: Get-ADOrganizationalUnit failed: $($_.Exception.Message)", $_) } +}Catch{$module.FailJson("Get-ADOrganizationalUnit failed: $($_.Exception.Message)", $_) } # set path if not defined to base domain if ($null -eq $path){ @@ -134,12 +133,12 @@ if ($null -eq $path){ }elseif ($($all_ous | Measure-Object | Select-Object -ExpandProperty Count) -gt 1) { $matched = $all_ous[0].DistinguishedName -match "DC=.+" }else{ - $module.FailJson("Line 137: Path was null and unable to determine default domain $($_.Exception.Message)", $_) + $module.FailJson("Path was null and unable to determine default domain $($_.Exception.Message)", $_) } if ($matched){ $path = $matches.Values[0] }else{ - $module.FailJson("Line 142: Unable to find default domain $($_.Exception.Message)", $_) + $module.FailJson("Unable to find default domain $($_.Exception.Message)", $_) } } @@ -164,7 +163,7 @@ if ($state -eq "present") { Try { New-ADOrganizationalUnit @params @onboard_extra_args -ProtectedFromAccidentalDeletion $protected -WhatIf:$check_mode }Catch { - $module.FailJson("Line 167: Failed to create organizational unit: $($_.Exception.Message)", $_) + $module.FailJson("Failed to create organizational unit: $($_.Exception.Message)", $_) } $module.Result.Changed = $true } @@ -174,7 +173,7 @@ if ($state -eq "present") { Try { Set-ADOrganizationalUnit -Identity "OU=$name,$path" @params @onboard_extra_args -WhatIf:$check_mode }Catch { - $module.FailJson("Line 177: Failed to update organizational unit: $($_.Exception.Message)", $_) + $module.FailJson("Failed to update organizational unit: $($_.Exception.Message)", $_) } } } @@ -186,7 +185,7 @@ if ($state -eq "absent") { # override protected from accidental deletion Set-ADOrganizationalUnit -Identity "OU=$name,$path" -ProtectedFromAccidentalDeletion $false @onboard_extra_args -Confirm:$False -WhatIf:$check_mode }Catch{ - $module.FailJson("Line 184: Failed to remove ProtectedFromAccidentalDeletion Lock: $($_.Exception.Message)", $_) + $module.FailJson("Failed to remove ProtectedFromAccidentalDeletion Lock: $($_.Exception.Message)", $_) } try{ # check recursive deletion @@ -197,7 +196,7 @@ if ($state -eq "absent") { } $module.Diff.after = "" } Catch { - $module.FailJson("Line 200: Failed to remove OU: $($_.Exception.Message)", $_) + $module.FailJson("Failed to remove OU: $($_.Exception.Message)", $_) } $module.Result.changed = $true } @@ -212,7 +211,7 @@ if (-not $check_mode) { $_.DistinguishedName -eq "OU=$name,$path" } }catch{ - $module.FailJson("Line 215: Failed to Get-ADOrganizationalUnit: $($_.Exception.Message)", $_) + $module.FailJson("Failed to Get-ADOrganizationalUnit: $($_.Exception.Message)", $_) } $module.Diff.after = Get-OuObject -Object $new_ou From 23ee0c3fdeff0805dc35c81ac3bdaeb72281d7f2 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 18:08:45 -0500 Subject: [PATCH 45/49] updating docs based on recommendations. --- plugins/modules/win_domain_ou.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 06edcfc8..78a63d80 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -78,7 +78,7 @@ properties: type: dict description: - - Free form dict of properties for the organizational unit. + - Free form dict of properties for the organizational unit. Follows LDAP property names, like StreetAddress or PostalCode. ''' EXAMPLES = r''' From 87e8ac3b60349f9770fb7cff6f802c306bcaf9cc Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:13:46 -0500 Subject: [PATCH 46/49] Update win_domain_ou.py --- plugins/modules/win_domain_ou.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/modules/win_domain_ou.py b/plugins/modules/win_domain_ou.py index 78a63d80..3ad17cc5 100644 --- a/plugins/modules/win_domain_ou.py +++ b/plugins/modules/win_domain_ou.py @@ -110,10 +110,10 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + StreetAddress: 1155 Perimeter Center West country: US description: EUC Business Unit - postal_code: 30189 + PostalCode: 30189 delegate_to: win-ad1.euc.vmware.lab - name: Ensure OU updated with new properties @@ -124,7 +124,7 @@ properties: city: Atlanta state: Georgia - managed_by: jzollo@vmware.com + managedBy: jzollo@vmware.com delegate_to: win-ad1.euc.vmware.lab ''' @@ -142,11 +142,11 @@ modified: protected: properties: - display_name: + displayName: description: city: - street_address: - postal_code: + streetAddress: + postalCode: country: - managed_by: + managedBY: ''' From 42e9d311455dfbb4f4d36761b49afc0ec19b0bab Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 19:14:54 -0500 Subject: [PATCH 47/49] Update quick.yml --- .../targets/win_domain_ou/tasks/quick.yml | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/tests/integration/targets/win_domain_ou/tasks/quick.yml b/tests/integration/targets/win_domain_ou/tasks/quick.yml index be27dd69..634d2d94 100644 --- a/tests/integration/targets/win_domain_ou/tasks/quick.yml +++ b/tests/integration/targets/win_domain_ou/tasks/quick.yml @@ -34,14 +34,14 @@ register: test1a failed_when: test1a is changed -- name: Ensure OU is present +- name: Ensure OU is present with path community.windows.win_domain_ou: name: End User Computing path: "{{ win_domain_ou_root_path }}" register: test2 failed_when: test2 is not changed -- name: Ensure OU is present (idempotence check) +- name: Ensure OU is present with path (idempotence check) community.windows.win_domain_ou: name: End User Computing path: "{{ win_domain_ou_root_path }}" @@ -56,10 +56,10 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + streetaddress: 1155 Perimeter Center West country: US description: EUC Business Unit - postal_code: 30189 + postalcode: 30189 register: test3 failed_when: test3 is not changed @@ -71,10 +71,10 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + streetaddress: 1155 Perimeter Center West country: US description: EUC Business Unit - postal_code: 30189 + postalcode: 30189 register: test3a failed_when: test3a is changed @@ -121,7 +121,7 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + streetaddress: 1155 Perimeter Center West register: test6 failed_when: test6 is not changed @@ -132,7 +132,7 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + streetaddress: 1155 Perimeter Center West register: test6a failed_when: test6a is changed @@ -143,7 +143,7 @@ properties: country: US description: EUC Business Unit - postalCode: 30189 + postalcode: 30189 register: test7 failed_when: test7 is not changed @@ -154,7 +154,7 @@ properties: country: US description: EUC Business Unit - postalCode: 30189 + postalcode: 30189 register: test7a failed_when: test7a is changed @@ -190,13 +190,17 @@ register: test9a failed_when: test9a is changed +- name: debug + ansible.builtin.debug: + var: test1a.ou.Name + - name: Assertions assert: that: - - test1a.ou.name == "AnsibleFest" - - test3a.ou.street_address == "1155 Perimeter Center West" - - test7a.ou.country == "US" - - test6a.ou.city == "Sandy Springs" + - test1a.ou.Name == "AnsibleFest" + - test3a.ou.StreetAddress == "1155 Perimeter Center West" + - test7a.ou.Country == "US" + - test6a.ou.City == "Sandy Springs" - name: Run Check Mode Tests block: @@ -215,10 +219,10 @@ properties: city: Sandy Springs state: Georgia - street_address: 1155 Perimeter Center West + streetaddress: 1155 Perimeter Center West country: US description: EUC Business Unit - postalCode: 30189 + postalcode: 30189 register: test2c failed_when: test2c is changed @@ -247,7 +251,7 @@ properties: city: Sandy Springs state: Georgia - streetAddress: 1155 Perimeter Center West + streetaddress: 1155 Perimeter Center West register: test5c failed_when: test5c is changed @@ -258,7 +262,7 @@ properties: country: US description: EUC Business Unit - postalCode: 30189 + postalcode: 30189 register: test6c failed_when: test6c is changed From a67dd3427428a885892a0ba3cfede975d3b2f8b3 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 20:37:15 -0500 Subject: [PATCH 48/49] Delete quick.yml --- .../targets/win_domain_ou/tasks/quick.yml | 284 ------------------ 1 file changed, 284 deletions(-) delete mode 100644 tests/integration/targets/win_domain_ou/tasks/quick.yml diff --git a/tests/integration/targets/win_domain_ou/tasks/quick.yml b/tests/integration/targets/win_domain_ou/tasks/quick.yml deleted file mode 100644 index 634d2d94..00000000 --- a/tests/integration/targets/win_domain_ou/tasks/quick.yml +++ /dev/null @@ -1,284 +0,0 @@ ---- -- name: Wait for ADWS - community.windows.win_wait_for_process: - process_name_exact: Microsoft.ActiveDirectory.WebServices - timeout: 120 - sleep: 5 - process_min_count: 1 - -- name: Try Import Again - block: - - name: Try Import-Module - ansible.windows.win_shell: | - whoami - try{Import-Module ActiveDirectory} - catch{ - start-sleep -seconds 5 - Import-Module ActiveDirectory - } - register: import_test2 - rescue: - - name: Try Import-Module - ansible.windows.win_shell: C:\Windows\system32\WindowsPowerShell\v1.0\Modules\ActiveDirectory\ActiveDirectory.psd1 - register: import_test3 - -- name: Ensure OU is present - community.windows.win_domain_ou: - name: AnsibleFest - register: test1 - failed_when: test1 is not changed - -- name: Ensure OU is present (idempotence check) - community.windows.win_domain_ou: - name: AnsibleFest - register: test1a - failed_when: test1a is changed - -- name: Ensure OU is present with path - community.windows.win_domain_ou: - name: End User Computing - path: "{{ win_domain_ou_root_path }}" - register: test2 - failed_when: test2 is not changed - -- name: Ensure OU is present with path (idempotence check) - community.windows.win_domain_ou: - name: End User Computing - path: "{{ win_domain_ou_root_path }}" - register: test2a - failed_when: test2a is changed - -- name: Ensure OU has updated properties - community.windows.win_domain_ou: - name: End User Computing - protected: true - path: "{{ win_domain_ou_root_path }}" - properties: - city: Sandy Springs - state: Georgia - streetaddress: 1155 Perimeter Center West - country: US - description: EUC Business Unit - postalcode: 30189 - register: test3 - failed_when: test3 is not changed - -- name: Ensure OU has updated properties (idempotence check) - community.windows.win_domain_ou: - name: End User Computing - protected: true - path: "{{ win_domain_ou_root_path }}" - properties: - city: Sandy Springs - state: Georgia - streetaddress: 1155 Perimeter Center West - country: US - description: EUC Business Unit - postalcode: 30189 - register: test3a - failed_when: test3a is changed - -- name: Ensure OU structure is present - community.windows.win_domain_ou: - name: "{{ item.name }}" - protected: false - path: "{{ item.path }}" - loop: "{{ win_domain_ou_structure }}" - register: test4 - failed_when: test4 is not changed - -- name: Ensure OU structure is present (idempotence check) - community.windows.win_domain_ou: - name: "{{ item.name }}" - protected: false - path: "{{ item.path }}" - loop: "{{ win_domain_ou_structure }}" - register: test4a - failed_when: test4a is changed - -- name: Ensure OU structure is absent, recursive - community.windows.win_domain_ou: - name: VMware - path: "{{ win_domain_ou_root_path }}" - state: absent - recursive: true - register: test5 - failed_when: test5 is not changed - -- name: Ensure OU structure is absent, recursive (idempotence check) - community.windows.win_domain_ou: - name: VMware - path: "{{ win_domain_ou_root_path }}" - state: absent - recursive: true - register: test5a - failed_when: test5a is changed - -- name: Ensure OU is present with specific properties - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - properties: - city: Sandy Springs - state: Georgia - streetaddress: 1155 Perimeter Center West - register: test6 - failed_when: test6 is not changed - -- name: Ensure OU is present with specific properties (idempotence check) - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - properties: - city: Sandy Springs - state: Georgia - streetaddress: 1155 Perimeter Center West - register: test6a - failed_when: test6a is changed - -- name: Ensure OU is present with specific properties added - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - properties: - country: US - description: EUC Business Unit - postalcode: 30189 - register: test7 - failed_when: test7 is not changed - -- name: Ensure OU is present with specific properties added (idempotence check) - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - properties: - country: US - description: EUC Business Unit - postalcode: 30189 - register: test7a - failed_when: test7a is changed - -- name: Ensure OU is absent - community.windows.win_domain_ou: - name: End User Computing - path: "{{ win_domain_ou_root_path }}" - state: absent - register: test8 - failed_when: test8 is not changed - -- name: Ensure OU is absent (idempotence check) - community.windows.win_domain_ou: - name: End User Computing - path: "{{ win_domain_ou_root_path }}" - state: absent - register: test8a - failed_when: test8a is changed - -- name: Ensure OU is absent - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - state: absent - register: test9 - failed_when: test9 is not changed - -- name: Ensure OU is absent (idempotence check) - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - state: absent - register: test9a - failed_when: test9a is changed - -- name: debug - ansible.builtin.debug: - var: test1a.ou.Name - -- name: Assertions - assert: - that: - - test1a.ou.Name == "AnsibleFest" - - test3a.ou.StreetAddress == "1155 Perimeter Center West" - - test7a.ou.Country == "US" - - test6a.ou.City == "Sandy Springs" - -- name: Run Check Mode Tests - block: - - name: Ensure OU is present - community.windows.win_domain_ou: - name: End User Computing - path: "{{ win_domain_ou_root_path }}" - register: test1c - failed_when: test1c is changed - - - name: Ensure OU has updated properties - community.windows.win_domain_ou: - name: End User Computing - protected: true - path: "{{ win_domain_ou_root_path }}" - properties: - city: Sandy Springs - state: Georgia - streetaddress: 1155 Perimeter Center West - country: US - description: EUC Business Unit - postalcode: 30189 - register: test2c - failed_when: test2c is changed - - - name: Ensure OU structure is present - community.windows.win_domain_ou: - name: "{{ item.name }}" - protected: false - path: "{{ item.path }}" - loop: "{{ win_domain_ou_structure }}" - register: test3c - failed_when: test3c is changed - - - name: Ensure OU structure is absent, recursive - community.windows.win_domain_ou: - name: VMware - path: "{{ win_domain_ou_root_path }}" - state: absent - recursive: true - register: test4c - failed_when: test4c is changed - - - name: Ensure OU is present with specific properties - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - properties: - city: Sandy Springs - state: Georgia - streetaddress: 1155 Perimeter Center West - register: test5c - failed_when: test5c is changed - - - name: Ensure OU is present with specific properties added - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - properties: - country: US - description: EUC Business Unit - postalcode: 30189 - register: test6c - failed_when: test6c is changed - - - name: Ensure OU is absent - community.windows.win_domain_ou: - name: End User Computing - path: "{{ win_domain_ou_root_path }}" - state: absent - register: test7c - failed_when: test7c is changed - - - name: Ensure OU is absent - community.windows.win_domain_ou: - name: VMW Atlanta - path: "{{ win_domain_ou_root_path }}" - state: absent - register: test8c - failed_when: test8c is changed - check_mode: true From 7999976d92d0cfe9f32fe7343de888aa54640a66 Mon Sep 17 00:00:00 2001 From: Larry <34108925+gamethis@users.noreply.github.com> Date: Thu, 16 Sep 2021 20:40:11 -0500 Subject: [PATCH 49/49] Update plugins/modules/win_domain_ou.ps1 Co-authored-by: Jordan Borean --- plugins/modules/win_domain_ou.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/modules/win_domain_ou.ps1 b/plugins/modules/win_domain_ou.ps1 index bd4dffec..f9c265b2 100644 --- a/plugins/modules/win_domain_ou.ps1 +++ b/plugins/modules/win_domain_ou.ps1 @@ -66,11 +66,6 @@ if ($module.Params.properties.count -ne 0){ $params.Add($_,$module.Params.properties.Item($_)) } } -# capture settings to know what we are doing -$module.Result.params = $params -$module.Result.extra_args = $extra_args -$module.Result.onboard_extra_args = $onboard_extra_args -$module.Result.properties = $properties Function Compare-OuObject { Param(